@@ -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;
@@ -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 */
@@ -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