Commit e8c4840d authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-wangxun-support-to-configure-rss'

Jiawen Wu says:

====================
net: wangxun: support to configure RSS

Implement ethtool ops for RSS configuration, and support multiple RSS
for multiple pools.
====================

Link: https://patch.msgid.link/20250926023843.34340-1-jiawenwu@trustnetic.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 1fb0e471 2a251b85
Loading
Loading
Loading
Loading
+136 −0
Original line number Diff line number Diff line
@@ -481,6 +481,142 @@ int wx_set_channels(struct net_device *dev,
}
EXPORT_SYMBOL(wx_set_channels);

u32 wx_rss_indir_size(struct net_device *netdev)
{
	struct wx *wx = netdev_priv(netdev);

	return wx_rss_indir_tbl_entries(wx);
}
EXPORT_SYMBOL(wx_rss_indir_size);

u32 wx_get_rxfh_key_size(struct net_device *netdev)
{
	return WX_RSS_KEY_SIZE;
}
EXPORT_SYMBOL(wx_get_rxfh_key_size);

static void wx_get_reta(struct wx *wx, u32 *indir)
{
	u32 reta_size = wx_rss_indir_tbl_entries(wx);
	u16 rss_m = wx->ring_feature[RING_F_RSS].mask;

	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags))
		rss_m = wx->ring_feature[RING_F_RSS].indices - 1;

	for (u32 i = 0; i < reta_size; i++)
		indir[i] = wx->rss_indir_tbl[i] & rss_m;
}

int wx_get_rxfh(struct net_device *netdev,
		struct ethtool_rxfh_param *rxfh)
{
	struct wx *wx = netdev_priv(netdev);

	rxfh->hfunc = ETH_RSS_HASH_TOP;

	if (rxfh->indir)
		wx_get_reta(wx, rxfh->indir);

	if (rxfh->key)
		memcpy(rxfh->key, wx->rss_key, WX_RSS_KEY_SIZE);

	return 0;
}
EXPORT_SYMBOL(wx_get_rxfh);

int wx_set_rxfh(struct net_device *netdev,
		struct ethtool_rxfh_param *rxfh,
		struct netlink_ext_ack *extack)
{
	struct wx *wx = netdev_priv(netdev);
	u32 reta_entries, i;

	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
	    rxfh->hfunc != ETH_RSS_HASH_TOP)
		return -EOPNOTSUPP;

	reta_entries = wx_rss_indir_tbl_entries(wx);
	/* Fill out the redirection table */
	if (rxfh->indir) {
		for (i = 0; i < reta_entries; i++)
			wx->rss_indir_tbl[i] = rxfh->indir[i];

		wx_store_reta(wx);
	}

	/* Fill out the rss hash key */
	if (rxfh->key) {
		memcpy(wx->rss_key, rxfh->key, WX_RSS_KEY_SIZE);
		wx_store_rsskey(wx);
	}

	return 0;
}
EXPORT_SYMBOL(wx_set_rxfh);

static const struct wx_rss_flow_map rss_flow_table[] = {
	{ TCP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_TCP },
	{ TCP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_TCP },
	{ UDP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_UDP },
	{ UDP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_UDP },
	{ SCTP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_SCTP },
	{ SCTP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_SCTP },
};

int wx_get_rxfh_fields(struct net_device *dev,
		       struct ethtool_rxfh_fields *nfc)
{
	struct wx *wx = netdev_priv(dev);

	nfc->data = RXH_IP_SRC | RXH_IP_DST;

	for (u32 i = 0; i < ARRAY_SIZE(rss_flow_table); i++) {
		const struct wx_rss_flow_map *entry = &rss_flow_table[i];

		if (entry->flow_type == nfc->flow_type) {
			if (wx->rss_flags & entry->flag)
				nfc->data |= entry->data;
			break;
		}
	}

	return 0;
}
EXPORT_SYMBOL(wx_get_rxfh_fields);

int wx_set_rxfh_fields(struct net_device *dev,
		       const struct ethtool_rxfh_fields *nfc,
		       struct netlink_ext_ack *extack)
{
	struct wx *wx = netdev_priv(dev);
	u8 flags = wx->rss_flags;

	if (!(nfc->data & RXH_IP_SRC) ||
	    !(nfc->data & RXH_IP_DST))
		return -EINVAL;

	for (u32 i = 0; i < ARRAY_SIZE(rss_flow_table); i++) {
		const struct wx_rss_flow_map *entry = &rss_flow_table[i];

		if (entry->flow_type == nfc->flow_type) {
			if (nfc->data & entry->data)
				flags |= entry->flag;
			else
				flags &= ~entry->flag;

			if (flags != wx->rss_flags) {
				wx->rss_flags = flags;
				wx_config_rss_field(wx);
			}

			return 0;
		}
	}

	return -EINVAL;
}
EXPORT_SYMBOL(wx_set_rxfh_fields);

u32 wx_get_msglevel(struct net_device *netdev)
{
	struct wx *wx = netdev_priv(netdev);
+12 −0
Original line number Diff line number Diff line
@@ -38,6 +38,18 @@ void wx_get_channels(struct net_device *dev,
		     struct ethtool_channels *ch);
int wx_set_channels(struct net_device *dev,
		    struct ethtool_channels *ch);
u32 wx_rss_indir_size(struct net_device *netdev);
u32 wx_get_rxfh_key_size(struct net_device *netdev);
int wx_get_rxfh(struct net_device *netdev,
		struct ethtool_rxfh_param *rxfh);
int wx_set_rxfh(struct net_device *netdev,
		struct ethtool_rxfh_param *rxfh,
		struct netlink_ext_ack *extack);
int wx_get_rxfh_fields(struct net_device *dev,
		       struct ethtool_rxfh_fields *cmd);
int wx_set_rxfh_fields(struct net_device *dev,
		       const struct ethtool_rxfh_fields *nfc,
		       struct netlink_ext_ack *extack);
u32 wx_get_msglevel(struct net_device *netdev);
void wx_set_msglevel(struct net_device *netdev, u32 data);
int wx_get_ts_info(struct net_device *dev,
+97 −36
Original line number Diff line number Diff line
@@ -1998,8 +1998,17 @@ static void wx_restore_vlan(struct wx *wx)
		wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid);
}

static void wx_store_reta(struct wx *wx)
u32 wx_rss_indir_tbl_entries(struct wx *wx)
{
	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags))
		return 64;
	else
		return 128;
}

void wx_store_reta(struct wx *wx)
{
	u32 reta_entries = wx_rss_indir_tbl_entries(wx);
	u8 *indir_tbl = wx->rss_indir_tbl;
	u32 reta = 0;
	u32 i;
@@ -2007,45 +2016,110 @@ static void wx_store_reta(struct wx *wx)
	/* Fill out the redirection table as follows:
	 *  - 8 bit wide entries containing 4 bit RSS index
	 */
	for (i = 0; i < WX_MAX_RETA_ENTRIES; i++) {
	for (i = 0; i < reta_entries; i++) {
		reta |= indir_tbl[i] << (i & 0x3) * 8;
		if ((i & 3) == 3) {
			if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags) &&
			    test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
				wr32(wx, WX_RDB_VMRSSTBL(i >> 2, wx->num_vfs), reta);
			else
				wr32(wx, WX_RDB_RSSTBL(i >> 2), reta);
			reta = 0;
		}
	}
}

static void wx_setup_reta(struct wx *wx)
void wx_store_rsskey(struct wx *wx)
{
	u16 rss_i = wx->ring_feature[RING_F_RSS].indices;
	u32 random_key_size = WX_RSS_KEY_SIZE / 4;
	u32 i, j;
	u32 key_size = WX_RSS_KEY_SIZE / 4;
	u32 i;

	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags)) {
		if (wx->mac.type == wx_mac_em)
			rss_i = 1;
		else
			rss_i = rss_i < 4 ? 4 : rss_i;
	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags) &&
	    test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
		for (i = 0; i < key_size; i++)
			wr32(wx, WX_RDB_VMRSSRK(i, wx->num_vfs),
			     wx->rss_key[i]);
	} else {
		for (i = 0; i < key_size; i++)
			wr32(wx, WX_RDB_RSSRK(i), wx->rss_key[i]);
	}
}

static void wx_setup_reta(struct wx *wx)
{
	/* Fill out hash function seeds */
	for (i = 0; i < random_key_size; i++)
		wr32(wx, WX_RDB_RSSRK(i), wx->rss_key[i]);
	wx_store_rsskey(wx);

	/* Fill out redirection table */
	if (!netif_is_rxfh_configured(wx->netdev)) {
		u16 rss_i = wx->ring_feature[RING_F_RSS].indices;
		u32 reta_entries = wx_rss_indir_tbl_entries(wx);
		u32 i, j;

		memset(wx->rss_indir_tbl, 0, sizeof(wx->rss_indir_tbl));

	for (i = 0, j = 0; i < WX_MAX_RETA_ENTRIES; i++, j++) {
		if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags)) {
			if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
				rss_i = rss_i < 2 ? 2 : rss_i;
			else
				rss_i = 1;
		}

		for (i = 0, j = 0; i < reta_entries; i++, j++) {
			if (j == rss_i)
				j = 0;

			wx->rss_indir_tbl[i] = j;
		}
	}

	wx_store_reta(wx);
}

void wx_config_rss_field(struct wx *wx)
{
	u32 rss_field;

	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags) &&
	    test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
		rss_field = rd32(wx, WX_RDB_PL_CFG(wx->num_vfs));
		rss_field &= ~WX_RDB_PL_CFG_RSS_MASK;
		rss_field |= FIELD_PREP(WX_RDB_PL_CFG_RSS_MASK, wx->rss_flags);
		wr32(wx, WX_RDB_PL_CFG(wx->num_vfs), rss_field);

		/* Enable global RSS and multiple RSS to make the RSS
		 * field of each pool take effect.
		 */
		wr32m(wx, WX_RDB_RA_CTL,
		      WX_RDB_RA_CTL_MULTI_RSS | WX_RDB_RA_CTL_RSS_EN,
		      WX_RDB_RA_CTL_MULTI_RSS | WX_RDB_RA_CTL_RSS_EN);
	} else {
		rss_field = rd32(wx, WX_RDB_RA_CTL);
		rss_field &= ~WX_RDB_RA_CTL_RSS_MASK;
		rss_field |= FIELD_PREP(WX_RDB_RA_CTL_RSS_MASK, wx->rss_flags);
		wr32(wx, WX_RDB_RA_CTL, rss_field);
	}
}

void wx_enable_rss(struct wx *wx, bool enable)
{
	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags) &&
	    test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
		if (enable)
			wr32m(wx, WX_RDB_PL_CFG(wx->num_vfs),
			      WX_RDB_PL_CFG_RSS_EN, WX_RDB_PL_CFG_RSS_EN);
		else
			wr32m(wx, WX_RDB_PL_CFG(wx->num_vfs),
			      WX_RDB_PL_CFG_RSS_EN, 0);
	} else {
		if (enable)
			wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN,
			      WX_RDB_RA_CTL_RSS_EN);
		else
			wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0);
	}
}

#define WX_RDB_RSS_PL_2		FIELD_PREP(GENMASK(31, 29), 1)
#define WX_RDB_RSS_PL_4		FIELD_PREP(GENMASK(31, 29), 2)
static void wx_setup_psrtype(struct wx *wx)
@@ -2076,27 +2150,12 @@ static void wx_setup_psrtype(struct wx *wx)

static void wx_setup_mrqc(struct wx *wx)
{
	u32 rss_field = 0;

	/* Disable indicating checksum in descriptor, enables RSS hash */
	wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_PCSD, WX_PSR_CTL_PCSD);

	/* Perform hash on these packet types */
	rss_field = WX_RDB_RA_CTL_RSS_IPV4 |
		    WX_RDB_RA_CTL_RSS_IPV4_TCP |
		    WX_RDB_RA_CTL_RSS_IPV4_UDP |
		    WX_RDB_RA_CTL_RSS_IPV6 |
		    WX_RDB_RA_CTL_RSS_IPV6_TCP |
		    WX_RDB_RA_CTL_RSS_IPV6_UDP;

	netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key));

	wx_config_rss_field(wx);
	wx_enable_rss(wx, wx->rss_enabled);
	wx_setup_reta(wx);

	if (wx->rss_enabled)
		rss_field |= WX_RDB_RA_CTL_RSS_EN;

	wr32(wx, WX_RDB_RA_CTL, rss_field);
}

/**
@@ -2389,6 +2448,8 @@ int wx_sw_init(struct wx *wx)
		wx_err(wx, "rss key allocation failed\n");
		return err;
	}
	wx->rss_flags = WX_RSS_FIELD_IPV4 | WX_RSS_FIELD_IPV4_TCP |
			WX_RSS_FIELD_IPV6 | WX_RSS_FIELD_IPV6_TCP;

	wx->mac_table = kcalloc(wx->mac.num_rar_entries,
				sizeof(struct wx_mac_addr),
+5 −0
Original line number Diff line number Diff line
@@ -39,6 +39,11 @@ void wx_set_rx_mode(struct net_device *netdev);
int wx_change_mtu(struct net_device *netdev, int new_mtu);
void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring);
u32 wx_rss_indir_tbl_entries(struct wx *wx);
void wx_store_reta(struct wx *wx);
void wx_store_rsskey(struct wx *wx);
void wx_config_rss_field(struct wx *wx);
void wx_enable_rss(struct wx *wx, bool enable);
void wx_configure_rx(struct wx *wx);
void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx);
+2 −8
Original line number Diff line number Diff line
@@ -3016,14 +3016,8 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
	struct wx *wx = netdev_priv(netdev);
	bool need_reset = false;

	if (features & NETIF_F_RXHASH) {
		wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN,
		      WX_RDB_RA_CTL_RSS_EN);
		wx->rss_enabled = true;
	} else {
		wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0);
		wx->rss_enabled = false;
	}
	wx->rss_enabled = !!(features & NETIF_F_RXHASH);
	wx_enable_rss(wx, wx->rss_enabled);

	netdev->features = features;

Loading