diff mbox series

[16/16] net-next/yunsilicon: Add change mtu

Message ID 20241209071101.3392590-17-tianx@yunsilicon.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [01/16] net-next/yunsilicon: Add yunsilicon xsc driver basic framework | expand

Checks

Context Check Description
netdev/series_format fail Series does not have a cover letter; Series longer than 15 patches (and no cover letter)
netdev/tree_selection success Guessed tree name to be net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 5 maintainers not CCed: andrew+netdev@lunn.ch kuba@kernel.org pabeni@redhat.com edumazet@google.com jacky@yunsilicon.com
netdev/build_clang success Errors and warnings before: 7 this patch: 7
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 288 this patch: 288
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

tianx Dec. 9, 2024, 7:11 a.m. UTC
From: Xin Tian <tianx@yunsilicon.com>

Add ndo_change_mtu

Signed-off-by: Xin Tian <tianx@yunsilicon.com>
Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
Signed-off-by: Lei Yan <jacky@yunsilicon.com>
---
 .../net/ethernet/yunsilicon/xsc/net/main.c    | 235 ++++++++++++++++--
 .../net/ethernet/yunsilicon/xsc/net/xsc_eth.h |   2 +
 .../ethernet/yunsilicon/xsc/net/xsc_queue.h   |   2 +-
 3 files changed, 213 insertions(+), 26 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/main.c b/drivers/net/ethernet/yunsilicon/xsc/net/main.c
index 1861b10a8..f749dca2f 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/net/main.c
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/main.c
@@ -1665,12 +1665,222 @@  static int xsc_eth_set_mac(struct net_device *netdev, void *addr)
 	return 0;
 }
 
+static void xsc_eth_rss_params_change(struct xsc_adapter *adapter, u32 change, void *modify)
+{
+	struct xsc_core_device *xdev = adapter->xdev;
+	struct xsc_rss_params *rss = &adapter->rss_param;
+	struct xsc_eth_params *params = &adapter->nic_param;
+	struct xsc_cmd_modify_nic_hca_mbox_in *in =
+		(struct xsc_cmd_modify_nic_hca_mbox_in *)modify;
+	u32 hash_field = 0;
+	int key_len;
+	u8 rss_caps_mask = 0;
+
+	if (xsc_get_user_mode(xdev))
+		return;
+
+	if (change & BIT(XSC_RSS_RXQ_DROP)) {
+		in->rss.rqn_base = cpu_to_be16(adapter->channels.rqn_base -
+				xdev->caps.raweth_rss_qp_id_base);
+		in->rss.rqn_num = 0;
+		rss_caps_mask |= BIT(XSC_RSS_RXQ_DROP);
+		goto rss_caps;
+	}
+
+	if (change & BIT(XSC_RSS_RXQ_UPDATE)) {
+		in->rss.rqn_base = cpu_to_be16(adapter->channels.rqn_base -
+				xdev->caps.raweth_rss_qp_id_base);
+		in->rss.rqn_num = cpu_to_be16(params->num_channels);
+		rss_caps_mask |= BIT(XSC_RSS_RXQ_UPDATE);
+	}
+
+	if (change & BIT(XSC_RSS_HASH_KEY_UPDATE)) {
+		key_len = min(sizeof(in->rss.hash_key), sizeof(rss->toeplitz_hash_key));
+		memcpy(&in->rss.hash_key, rss->toeplitz_hash_key, key_len);
+		rss_caps_mask |= BIT(XSC_RSS_HASH_KEY_UPDATE);
+	}
+
+	if (change & BIT(XSC_RSS_HASH_TEMP_UPDATE)) {
+		hash_field = rss->rx_hash_fields[XSC_TT_IPV4_TCP] |
+				rss->rx_hash_fields[XSC_TT_IPV6_TCP];
+		in->rss.hash_tmpl = cpu_to_be32(hash_field);
+		rss_caps_mask |= BIT(XSC_RSS_HASH_TEMP_UPDATE);
+	}
+
+	if (change & BIT(XSC_RSS_HASH_FUNC_UPDATE)) {
+		in->rss.hfunc = xsc_hash_func_type(rss->hfunc);
+		rss_caps_mask |= BIT(XSC_RSS_HASH_FUNC_UPDATE);
+	}
+
+rss_caps:
+	if (rss_caps_mask) {
+		in->rss.caps_mask = rss_caps_mask;
+		in->rss.rss_en = 1;
+		in->nic.caps_mask = cpu_to_be16(BIT(XSC_TBM_CAP_RSS));
+		in->nic.caps = in->nic.caps_mask;
+	}
+}
+
+static int xsc_eth_modify_nic_hca(struct xsc_adapter *adapter, u32 flags)
+{
+	struct xsc_core_device *xdev = adapter->xdev;
+	struct xsc_cmd_modify_nic_hca_mbox_in in = {};
+	struct xsc_cmd_modify_nic_hca_mbox_out out = {};
+	int err = 0;
+
+	in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_MODIFY_NIC_HCA);
+
+	xsc_eth_rss_params_change(adapter, flags, &in);
+	if (in.rss.caps_mask) {
+		err = xsc_cmd_exec(xdev, &in, sizeof(in), &out, sizeof(out));
+		if (err || out.hdr.status) {
+			xsc_core_err(xdev, "failed!! err=%d, status=%u\n",
+				     err, out.hdr.status);
+			return -ENOEXEC;
+		}
+	}
+
+	return 0;
+}
+
+static int xsc_safe_switch_channels(struct xsc_adapter *adapter,
+				    xsc_eth_fp_preactivate preactivate)
+{
+	struct net_device *netdev = adapter->netdev;
+	int carrier_ok;
+	int ret = 0;
+
+	adapter->status = XSCALE_ETH_DRIVER_CLOSE;
+
+	carrier_ok = netif_carrier_ok(netdev);
+	netif_carrier_off(netdev);
+	ret = xsc_eth_modify_nic_hca(adapter, BIT(XSC_RSS_RXQ_DROP));
+	if (ret)
+		goto close_channels;
+
+	xsc_eth_deactivate_priv_channels(adapter);
+	xsc_eth_close_channels(adapter);
+
+	if (preactivate) {
+		ret = preactivate(adapter);
+		if (ret)
+			goto out;
+	}
+
+	ret = xsc_eth_open_channels(adapter);
+	if (ret)
+		goto close_channels;
+
+	xsc_eth_activate_priv_channels(adapter);
+	ret = xsc_eth_modify_nic_hca(adapter, BIT(XSC_RSS_RXQ_UPDATE));
+	if (ret)
+		goto close_channels;
+
+	adapter->status = XSCALE_ETH_DRIVER_OK;
+
+	goto out;
+
+close_channels:
+	xsc_eth_deactivate_priv_channels(adapter);
+	xsc_eth_close_channels(adapter);
+
+out:
+	if (carrier_ok)
+		netif_carrier_on(netdev);
+	xsc_core_dbg(adapter->xdev, "channels=%d, mtu=%d, err=%d\n",
+		     adapter->nic_param.num_channels,
+		     adapter->nic_param.mtu, ret);
+	return ret;
+}
+
+static int xsc_eth_set_hw_mtu(struct xsc_core_device *dev, u16 mtu, u16 rx_buf_sz)
+{
+	struct xsc_set_mtu_mbox_in in;
+	struct xsc_set_mtu_mbox_out out;
+	int ret;
+
+	memset(&in, 0, sizeof(struct xsc_set_mtu_mbox_in));
+	memset(&out, 0, sizeof(struct xsc_set_mtu_mbox_out));
+
+	in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_SET_MTU);
+	in.mtu = cpu_to_be16(mtu);
+	in.rx_buf_sz_min = cpu_to_be16(rx_buf_sz);
+	in.mac_port = dev->mac_port;
+
+	ret = xsc_cmd_exec(dev, &in, sizeof(struct xsc_set_mtu_mbox_in), &out,
+			   sizeof(struct xsc_set_mtu_mbox_out));
+	if (ret || out.hdr.status) {
+		xsc_core_err(dev, "failed to set hw_mtu=%u rx_buf_sz=%u, err=%d, status=%d\n",
+			     mtu, rx_buf_sz, ret, out.hdr.status);
+		ret = -ENOEXEC;
+	}
+
+	return ret;
+}
+
+static int xsc_eth_nic_mtu_changed(struct xsc_adapter *priv)
+{
+	u32 new_mtu = priv->nic_param.mtu;
+	int ret;
+
+	ret = xsc_eth_set_hw_mtu(priv->xdev, XSC_SW2HW_MTU(new_mtu),
+				 XSC_SW2HW_RX_PKT_LEN(new_mtu));
+
+	return ret;
+}
+
+static int xsc_eth_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct xsc_adapter *adapter = netdev_priv(netdev);
+	int old_mtu = netdev->mtu;
+	int ret = 0;
+	int max_buf_len = 0;
+
+	if (new_mtu > netdev->max_mtu || new_mtu < netdev->min_mtu) {
+		netdev_err(netdev, "%s: Bad MTU (%d), valid range is: [%d..%d]\n",
+			   __func__, new_mtu, netdev->min_mtu, netdev->max_mtu);
+		return -EINVAL;
+	}
+
+	if (!xsc_rx_is_linear_skb(new_mtu)) {
+		max_buf_len = adapter->xdev->caps.recv_ds_num * PAGE_SIZE;
+		if (new_mtu > max_buf_len) {
+			netdev_err(netdev, "Bad MTU (%d), max buf len is %d\n",
+				   new_mtu, max_buf_len);
+			return -EINVAL;
+		}
+	}
+	mutex_lock(&adapter->status_lock);
+	adapter->nic_param.mtu = new_mtu;
+	if (adapter->status != XSCALE_ETH_DRIVER_OK) {
+		ret = xsc_eth_nic_mtu_changed(adapter);
+		if (ret)
+			adapter->nic_param.mtu = old_mtu;
+		else
+			netdev->mtu = adapter->nic_param.mtu;
+		goto out;
+	}
+
+	ret = xsc_safe_switch_channels(adapter, xsc_eth_nic_mtu_changed);
+	if (ret)
+		goto out;
+
+	netdev->mtu = adapter->nic_param.mtu;
+
+out:
+	mutex_unlock(&adapter->status_lock);
+	xsc_core_info(adapter->xdev, "mtu change from %d to %d, new_mtu=%d, err=%d\n",
+		      old_mtu, netdev->mtu, new_mtu, ret);
+	return ret;
+}
+
 static const struct net_device_ops xsc_netdev_ops = {
 	.ndo_open		= xsc_eth_open,
 	.ndo_stop		= xsc_eth_close,
 	.ndo_start_xmit		= xsc_eth_xmit_start,
 	.ndo_get_stats64	= xsc_eth_get_stats,
 	.ndo_set_mac_address	= xsc_eth_set_mac,
+	.ndo_change_mtu		= xsc_eth_change_mtu,
 };
 
 static void xsc_eth_build_nic_netdev(struct xsc_adapter *adapter)
@@ -1724,31 +1934,6 @@  static void xsc_eth_nic_cleanup(struct xsc_adapter *adapter)
 	kfree(adapter->txq2sq);
 }
 
-static int xsc_eth_set_hw_mtu(struct xsc_core_device *dev, u16 mtu, u16 rx_buf_sz)
-{
-	struct xsc_set_mtu_mbox_in in;
-	struct xsc_set_mtu_mbox_out out;
-	int ret;
-
-	memset(&in, 0, sizeof(struct xsc_set_mtu_mbox_in));
-	memset(&out, 0, sizeof(struct xsc_set_mtu_mbox_out));
-
-	in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_SET_MTU);
-	in.mtu = cpu_to_be16(mtu);
-	in.rx_buf_sz_min = cpu_to_be16(rx_buf_sz);
-	in.mac_port = dev->mac_port;
-
-	ret = xsc_cmd_exec(dev, &in, sizeof(struct xsc_set_mtu_mbox_in), &out,
-			   sizeof(struct xsc_set_mtu_mbox_out));
-	if (ret || out.hdr.status) {
-		xsc_core_err(dev, "failed to set hw_mtu=%u rx_buf_sz=%u, err=%d, status=%d\n",
-			     mtu, rx_buf_sz, ret, out.hdr.status);
-		ret = -ENOEXEC;
-	}
-
-	return ret;
-}
-
 static int xsc_eth_get_mac(struct xsc_core_device *dev, char *mac)
 {
 	struct xsc_query_eth_mac_mbox_out *out;
diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/xsc_eth.h b/drivers/net/ethernet/yunsilicon/xsc/net/xsc_eth.h
index 96c1954ef..9b261f116 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/net/xsc_eth.h
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/xsc_eth.h
@@ -53,4 +53,6 @@  struct xsc_adapter {
 	struct xsc_stats *stats;
 };
 
+typedef int (*xsc_eth_fp_preactivate)(struct xsc_adapter *priv);
+
 #endif /* XSC_ETH_H */
diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/xsc_queue.h b/drivers/net/ethernet/yunsilicon/xsc/net/xsc_queue.h
index 2a6740896..b24a686f1 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/net/xsc_queue.h
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/xsc_queue.h
@@ -1,6 +1,6 @@ 
 /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
+ * Copyright (C) 2021-2024, Shanghai Yunsilicon Technology Co., Ltd.
  * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two