From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from canpmsgout04.his.huawei.com (canpmsgout04.his.huawei.com [113.46.200.219]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F2CC83DB623; Mon, 27 Jul 2026 06:55:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.219 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785135327; cv=none; b=MFrzvrrNdznYFCqjDPJzqlYAa4XRjdzUNpBJTD5VXMF6A/sAsdrmPLGnnthsRaF0/bP4F0PQIX/S8+PajpPtv82G0m7u5q7fWAaca9FLnmRLaH3kZytt6BYA0RKHKDfg9JCh/smHOXltGi7QN8uRPezHPgv12X0HyM3SJrDI0xo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785135327; c=relaxed/simple; bh=YnGF5o/Gzc+Wy46N3z0ANUD3V2vRmkUYNXX9BJj8tRY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ar5OCOVAuq5LdyX3I8fqZTabBqwFp5b1iCXFncTeSeHo+mUMt4m5VSC5qTGKPq6fF3y9zVISrDsxsP6MSWE154Q6RsZbQsk/GfgD3C87OEiupXf+0F/29l3t9O2p80By0ahZo/WSPjO7vgxSXRs1fIAErOTHvjdvVYNKEVsVOeo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=4dTihtuJ; arc=none smtp.client-ip=113.46.200.219 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="4dTihtuJ" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=icFWZhD4/KyEHkuaTuj2k+hVbV6FOmsWiRrdXIEGd0I=; b=4dTihtuJx7mAaZxvsxoLcz7tUwZrfXaVlpHE8f/hGvX3Vj2L4o6vHMRFQCD5uWbQ+a0EeTii+ suOjll1z4QyvtNXT4WMD5jf+HIN7gs5rI6PlaxF2kXmKIJs3cdLyldCWkiTa7ligQGP7dMcAMaG h4Cqt7oY9n/5prMZ2QTAJ7E= Received: from mail.maildlp.com (unknown [172.19.162.144]) by canpmsgout04.his.huawei.com (SkyGuard) with ESMTPS id 4h7pyW0V33z1prlh; Mon, 27 Jul 2026 14:45:55 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id CDE6140538; Mon, 27 Jul 2026 14:55:22 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.189.124) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Mon, 27 Jul 2026 14:55:21 +0800 From: Fan Gong To: Fan Gong , Wu Di , Teng Peisen , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Ioana Ciornei , Mohsin Bashir , Dimitri Daskalakis , Harshitha Ramamurthy CC: , , Chen Anwen , He Wei , luosifu , Xin Guo , Zhou Shuai , Wu Like , Shi Jing , Zheng Jiezhen , Maxime Chevallier Subject: [PATCH net-next v12 7/8] hinic3: Add ethtool rss ops Date: Mon, 27 Jul 2026 14:54:58 +0800 Message-ID: X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To kwepemf100013.china.huawei.com (7.202.181.12) Implement following ethtool callback function: .get_rxnfc .set_rxnfc .get_channels .set_channels .get_rxfh_indir_size .get_rxfh_key_size .get_rxfh .set_rxfh These callbacks allow users to utilize ethtool for detailed RSS parameters configuration and monitoring. Co-developed-by: Wu Di Signed-off-by: Wu Di Co-developed-by: Teng Peisen Signed-off-by: Teng Peisen Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_ethtool.c | 10 + .../huawei/hinic3/hinic3_mgmt_interface.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_rss.c | 566 +++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_rss.h | 20 + 4 files changed, 596 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c index 4177aed877ab..1702136297a9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c @@ -16,6 +16,7 @@ #include "hinic3_hw_comm.h" #include "hinic3_nic_dev.h" #include "hinic3_nic_cfg.h" +#include "hinic3_rss.h" #define HINIC3_MGMT_VERSION_MAX_LEN 32 /* Coalesce time properties in microseconds */ @@ -1297,6 +1298,15 @@ static const struct ethtool_ops hinic3_ethtool_ops = { .get_pause_stats = hinic3_get_pause_stats, .get_coalesce = hinic3_get_coalesce, .set_coalesce = hinic3_set_coalesce, + .get_rxnfc = hinic3_get_rxnfc, + .set_rxnfc = hinic3_set_rxnfc, + .get_rx_ring_count = hinic3_get_rx_ring_count, + .get_channels = hinic3_get_channels, + .set_channels = hinic3_set_channels, + .get_rxfh_indir_size = hinic3_get_rxfh_indir_size, + .get_rxfh_key_size = hinic3_get_rxfh_key_size, + .get_rxfh = hinic3_get_rxfh, + .set_rxfh = hinic3_set_rxfh, }; void hinic3_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 76c691f82703..3c1263ff99ff 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -282,6 +282,7 @@ enum l2nic_cmd { L2NIC_CMD_SET_VLAN_FILTER_EN = 26, L2NIC_CMD_SET_RX_VLAN_OFFLOAD = 27, L2NIC_CMD_CFG_RSS = 60, + L2NIC_CMD_GET_RSS_CTX_TBL = 62, L2NIC_CMD_CFG_RSS_HASH_KEY = 63, L2NIC_CMD_CFG_RSS_HASH_ENGINE = 64, L2NIC_CMD_SET_RSS_CTX_TBL = 65, @@ -301,6 +302,7 @@ enum l2nic_ucode_cmd { L2NIC_UCODE_CMD_MODIFY_QUEUE_CTX = 0, L2NIC_UCODE_CMD_CLEAN_QUEUE_CTX = 1, L2NIC_UCODE_CMD_SET_RSS_INDIR_TBL = 4, + L2NIC_UCODE_CMD_GET_RSS_INDIR_TBL = 6, }; /* hilink mac group command */ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c index 25db74d8c7dd..2f50249e9337 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c @@ -155,7 +155,7 @@ static int hinic3_set_rss_type(struct hinic3_hwdev *hwdev, L2NIC_CMD_SET_RSS_CTX_TBL, &msg_params); if (ctx_tbl.msg_head.status == MGMT_STATUS_CMD_UNSUPPORTED) { - return MGMT_STATUS_CMD_UNSUPPORTED; + return -EOPNOTSUPP; } else if (err || ctx_tbl.msg_head.status) { dev_err(hwdev->dev, "mgmt Failed to set rss context offload, err: %d, status: 0x%x\n", err, ctx_tbl.msg_head.status); @@ -165,6 +165,41 @@ static int hinic3_set_rss_type(struct hinic3_hwdev *hwdev, return 0; } +static int hinic3_get_rss_type(struct hinic3_hwdev *hwdev, + struct hinic3_rss_type *rss_type) +{ + struct l2nic_cmd_rss_ctx_tbl ctx_tbl = {}; + struct mgmt_msg_params msg_params = {}; + int err; + + ctx_tbl.func_id = hinic3_global_func_id(hwdev); + + mgmt_msg_params_init_default(&msg_params, &ctx_tbl, sizeof(ctx_tbl)); + + err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_GET_RSS_CTX_TBL, + &msg_params); + if (ctx_tbl.msg_head.status == MGMT_STATUS_CMD_UNSUPPORTED) { + return -EOPNOTSUPP; + } else if (err || ctx_tbl.msg_head.status) { + dev_err(hwdev->dev, "Failed to get hash type, err: %d, status: 0x%x\n", + err, ctx_tbl.msg_head.status); + return -EINVAL; + } + + rss_type->ipv4 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, IPV4); + rss_type->ipv6 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, IPV6); + rss_type->ipv6_ext = L2NIC_RSS_TYPE_GET(ctx_tbl.context, IPV6_EXT); + rss_type->tcp_ipv4 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV4); + rss_type->tcp_ipv6 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6); + rss_type->tcp_ipv6_ext = L2NIC_RSS_TYPE_GET(ctx_tbl.context, + TCP_IPV6_EXT); + rss_type->udp_ipv4 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV4); + rss_type->udp_ipv6 = L2NIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV6); + + return 0; +} + static int hinic3_rss_cfg_hash_type(struct hinic3_hwdev *hwdev, u8 opcode, enum hinic3_rss_hash_type *type) { @@ -264,7 +299,8 @@ static int hinic3_set_hw_rss_parameters(struct net_device *netdev, u8 rss_en) if (err) return err; - hinic3_fillout_indir_tbl(netdev, nic_dev->rss_indir); + if (!netif_is_rxfh_configured(netdev)) + hinic3_fillout_indir_tbl(netdev, nic_dev->rss_indir); err = hinic3_config_rss_hw_resource(netdev, nic_dev->rss_indir); if (err) @@ -334,3 +370,529 @@ void hinic3_try_to_enable_rss(struct net_device *netdev) clear_bit(HINIC3_RSS_ENABLE, &nic_dev->flags); nic_dev->q_params.num_qps = nic_dev->max_qps; } + +static int hinic3_set_l4_rss_hash_ops(const struct ethtool_rxnfc *cmd, + struct hinic3_rss_type *rss_type) +{ + u8 rss_l4_en; + + switch (cmd->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + rss_l4_en = 0; + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + rss_l4_en = 1; + break; + default: + return -EINVAL; + } + + switch (cmd->flow_type) { + case TCP_V4_FLOW: + rss_type->tcp_ipv4 = rss_l4_en; + break; + case TCP_V6_FLOW: + rss_type->tcp_ipv6 = rss_l4_en; + break; + case UDP_V4_FLOW: + rss_type->udp_ipv4 = rss_l4_en; + break; + case UDP_V6_FLOW: + rss_type->udp_ipv6 = rss_l4_en; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int hinic3_update_rss_hash_opts(struct net_device *netdev, + struct ethtool_rxnfc *cmd, + struct hinic3_rss_type *rss_type) +{ + int err; + + switch (cmd->flow_type) { + case TCP_V4_FLOW: + case TCP_V6_FLOW: + case UDP_V4_FLOW: + case UDP_V6_FLOW: + err = hinic3_set_l4_rss_hash_ops(cmd, rss_type); + if (err) + return err; + + break; + case IPV4_FLOW: + rss_type->ipv4 = (cmd->data != 0) ? 1 : 0; + break; + case IPV6_FLOW: + rss_type->ipv6 = (cmd->data != 0) ? 1 : 0; + break; + default: + netdev_err(netdev, "Unsupported flow type\n"); + return -EINVAL; + } + + return 0; +} + +static int hinic3_set_rss_hash_opts(struct net_device *netdev, + struct ethtool_rxnfc *cmd) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + struct hinic3_rss_type rss_type; + int err; + + if (!test_bit(HINIC3_RSS_ENABLE, &nic_dev->flags)) { + cmd->data = 0; + netdev_err(netdev, "RSS is disable, not support to set flow-hash\n"); + return -EOPNOTSUPP; + } + + /* RSS only supports hashing of IP addresses and L4 ports */ + if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) + return -EINVAL; + + /* Both IP addresses must be part of the hash tuple */ + if (cmd->data && + (!(cmd->data & RXH_IP_SRC) || !(cmd->data & RXH_IP_DST))) + return -EINVAL; + + /* L4 hash bits are not valid for pure L3 flow types */ + if ((cmd->flow_type == IPV4_FLOW || cmd->flow_type == IPV6_FLOW) && + (cmd->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3))) + return -EINVAL; + + err = hinic3_get_rss_type(nic_dev->hwdev, &rss_type); + if (err) { + netdev_err(netdev, "Failed to get rss type\n"); + return err; + } + + err = hinic3_update_rss_hash_opts(netdev, cmd, &rss_type); + if (err) + return err; + + err = hinic3_set_rss_type(nic_dev->hwdev, rss_type); + if (err) { + netdev_err(netdev, "Failed to set rss type\n"); + return err; + } + + nic_dev->rss_type = rss_type; + + return 0; +} + +static void convert_rss_l3_type(u8 rss_opt, struct ethtool_rxnfc *cmd) +{ + if (!rss_opt) + cmd->data &= ~(RXH_IP_SRC | RXH_IP_DST); +} + +static void convert_rss_l4_type(u8 rss_opt, struct ethtool_rxnfc *cmd) +{ + if (rss_opt) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +} + +static int hinic3_convert_rss_type(struct net_device *netdev, + struct hinic3_rss_type *rss_type, + struct ethtool_rxnfc *cmd) +{ + cmd->data = RXH_IP_SRC | RXH_IP_DST; + switch (cmd->flow_type) { + case TCP_V4_FLOW: + convert_rss_l4_type(rss_type->tcp_ipv4, cmd); + break; + case TCP_V6_FLOW: + convert_rss_l4_type(rss_type->tcp_ipv6, cmd); + break; + case UDP_V4_FLOW: + convert_rss_l4_type(rss_type->udp_ipv4, cmd); + break; + case UDP_V6_FLOW: + convert_rss_l4_type(rss_type->udp_ipv6, cmd); + break; + case IPV4_FLOW: + convert_rss_l3_type(rss_type->ipv4, cmd); + break; + case IPV6_FLOW: + convert_rss_l3_type(rss_type->ipv6, cmd); + break; + default: + netdev_err(netdev, "Unsupported flow type\n"); + cmd->data = 0; + return -EINVAL; + } + + return 0; +} + +static int hinic3_get_rss_hash_opts(struct net_device *netdev, + struct ethtool_rxnfc *cmd) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + struct hinic3_rss_type rss_type; + int err; + + cmd->data = 0; + + if (!test_bit(HINIC3_RSS_ENABLE, &nic_dev->flags)) + return 0; + + err = hinic3_get_rss_type(nic_dev->hwdev, &rss_type); + if (err) { + netdev_err(netdev, "Failed to get rss type\n"); + return err; + } + + return hinic3_convert_rss_type(netdev, &rss_type, cmd); +} + +u32 hinic3_get_rx_ring_count(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + + return nic_dev->q_params.num_qps; +} + +int hinic3_get_rxnfc(struct net_device *netdev, + struct ethtool_rxnfc *cmd, u32 *rule_locs) +{ + int err; + + switch (cmd->cmd) { + case ETHTOOL_GRXFH: + err = hinic3_get_rss_hash_opts(netdev, cmd); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +int hinic3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) +{ + int err; + + switch (cmd->cmd) { + case ETHTOOL_SRXFH: + err = hinic3_set_rss_hash_opts(netdev, cmd); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static u16 hinic3_max_channels(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + u8 tcs = netdev_get_num_tc(netdev); + + return tcs ? nic_dev->max_qps / tcs : nic_dev->max_qps; +} + +static u16 hinic3_curr_channels(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + + if (netif_running(netdev)) + return nic_dev->q_params.num_qps ? + nic_dev->q_params.num_qps : 1; + else + return min_t(u16, hinic3_max_channels(netdev), + nic_dev->q_params.num_qps); +} + +void hinic3_get_channels(struct net_device *netdev, + struct ethtool_channels *channels) +{ + channels->max_rx = 0; + channels->max_tx = 0; + channels->max_other = 0; + /* report maximum channels */ + channels->max_combined = hinic3_max_channels(netdev); + channels->rx_count = 0; + channels->tx_count = 0; + channels->other_count = 0; + /* report flow director queues as maximum channels */ + channels->combined_count = hinic3_curr_channels(netdev); +} + +static int +hinic3_validate_channel_parameter(struct net_device *netdev, + const struct ethtool_channels *channels) +{ + u16 max_channel = hinic3_max_channels(netdev); + unsigned int count = channels->combined_count; + + if (!count) { + netdev_err(netdev, "Unsupported combined_count=0\n"); + return -EINVAL; + } + + if (channels->tx_count || channels->rx_count || channels->other_count) { + netdev_err(netdev, "Setting rx/tx/other count not supported\n"); + return -EINVAL; + } + + if (count > max_channel) { + netdev_err(netdev, "Combined count %u exceed limit %u\n", count, + max_channel); + return -EINVAL; + } + + return 0; +} + +static int hinic3_rss_update_num_qps_and_reprogram(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + int err; + + if (!netif_is_rxfh_configured(netdev)) { + hinic3_fillout_indir_tbl(netdev, nic_dev->rss_indir); + hinic3_rss_set_indir_tbl(nic_dev->hwdev, nic_dev->rss_indir); + } + + if (!netif_running(netdev)) + return 0; + + err = hinic3_set_hw_rss_parameters(netdev, 1); + if (err) + netdev_err(netdev, + "Failed to update RSS parameters after changing channels\n"); + + return err; +} + +int hinic3_set_channels(struct net_device *netdev, + struct ethtool_channels *channels) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + unsigned int count = channels->combined_count; + struct hinic3_dyna_txrxq_params q_params; + u16 old_num_qps; + int err; + + err = hinic3_validate_channel_parameter(netdev, channels); + if (err) + return err; + + if (!test_bit(HINIC3_RSS_ENABLE, &nic_dev->flags)) { + netdev_err(netdev, "This function doesn't support RSS, only support 1 queue pair\n"); + return -EOPNOTSUPP; + } + + old_num_qps = nic_dev->q_params.num_qps; + + netdev_dbg(netdev, "Set max combined queue number from %u to %u\n", + old_num_qps, count); + + if (netif_running(netdev)) { + q_params = nic_dev->q_params; + q_params.num_qps = (u16)count; + q_params.txqs_res = NULL; + q_params.rxqs_res = NULL; + q_params.irq_cfg = NULL; + + err = hinic3_change_channel_settings(netdev, &q_params); + if (err) { + netdev_err(netdev, "Failed to change channel settings\n"); + return err; + } + } else { + nic_dev->q_params.num_qps = (u16)count; + } + + err = hinic3_rss_update_num_qps_and_reprogram(netdev); + if (err) { + if (netif_running(netdev)) { + q_params.num_qps = old_num_qps; + if (hinic3_change_channel_settings(netdev, &q_params)) + netdev_err(netdev, "Failed to rollback channel settings after RSS error\n"); + } else { + nic_dev->q_params.num_qps = old_num_qps; + } + return err; + } + + return 0; +} + +u32 hinic3_get_rxfh_indir_size(struct net_device *netdev) +{ + return L2NIC_RSS_INDIR_SIZE; +} + +static int hinic3_set_rss_rxfh(struct net_device *netdev, + const u32 *indir, u8 *key) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + u16 temp_indir[L2NIC_RSS_INDIR_SIZE]; + int err; + u32 i; + + if (indir) { + for (i = 0; i < L2NIC_RSS_INDIR_SIZE; i++) + temp_indir[i] = (u16)indir[i]; + + err = hinic3_rss_set_indir_tbl(nic_dev->hwdev, temp_indir); + if (err) { + netdev_err(netdev, "Failed to set rss indir table\n"); + return err; + } + + memcpy(nic_dev->rss_indir, temp_indir, sizeof(temp_indir)); + } + + if (key) { + err = hinic3_rss_set_hash_key(nic_dev->hwdev, key); + if (err) { + netdev_err(netdev, "Failed to set rss key\n"); + return err; + } + + memcpy(nic_dev->rss_hkey, key, L2NIC_RSS_KEY_SIZE); + } + + return 0; +} + +u32 hinic3_get_rxfh_key_size(struct net_device *netdev) +{ + return L2NIC_RSS_KEY_SIZE; +} + +static int hinic3_rss_get_indir_tbl(struct hinic3_hwdev *hwdev, + u32 *indir_table) +{ + struct hinic3_cmd_buf_pair pair; + __le16 *indir_tbl = NULL; + int err, i; + + err = hinic3_cmd_buf_pair_init(hwdev, &pair); + if (err) { + dev_err(hwdev->dev, "Failed to allocate cmd_buf.\n"); + return err; + } + + memset(pair.in->buf, 0, le16_to_cpu(pair.in->size)); + memset(pair.out->buf, 0, le16_to_cpu(pair.out->size)); + + err = hinic3_cmdq_detail_resp(hwdev, MGMT_MOD_L2NIC, + L2NIC_UCODE_CMD_GET_RSS_INDIR_TBL, + pair.in, pair.out, NULL); + if (err) { + dev_err(hwdev->dev, "Failed to get rss indir table\n"); + goto err_get_indir_tbl; + } + + indir_tbl = (__force __le16 *)pair.out->buf; + + /* Note: The firmware internally handles the byte order for the GET + * response. Unlike the SET path, no swab32 conversion is needed here. + */ + for (i = 0; i < L2NIC_RSS_INDIR_SIZE; i++) + indir_table[i] = le16_to_cpu(*(indir_tbl + i)); + +err_get_indir_tbl: + hinic3_cmd_buf_pair_uninit(hwdev, &pair); + + return err; +} + +int hinic3_get_rxfh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + int err = 0; + + if (!test_bit(HINIC3_RSS_ENABLE, &nic_dev->flags)) { + netdev_err(netdev, "Rss is disabled\n"); + return -EOPNOTSUPP; + } + + rxfh->hfunc = + nic_dev->rss_hash_type == HINIC3_RSS_HASH_ENGINE_TYPE_XOR ? + ETH_RSS_HASH_XOR : ETH_RSS_HASH_TOP; + + if (rxfh->indir) { + err = hinic3_rss_get_indir_tbl(nic_dev->hwdev, rxfh->indir); + if (err) + return err; + } + + if (rxfh->key) + memcpy(rxfh->key, nic_dev->rss_hkey, L2NIC_RSS_KEY_SIZE); + + return err; +} + +static int hinic3_set_hw_hash_type(struct net_device *netdev, + enum hinic3_rss_hash_type new_rss_hash_type) +{ + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + int err; + + if (new_rss_hash_type == nic_dev->rss_hash_type) + return 0; + + err = hinic3_rss_set_hash_type(nic_dev->hwdev, new_rss_hash_type); + if (err) { + netdev_err(netdev, "Failed to set RSS hash type to HW\n"); + return err; + } + + nic_dev->rss_hash_type = new_rss_hash_type; + + return 0; +} + +int hinic3_set_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + enum hinic3_rss_hash_type old_hash_type, new_hash_type; + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); + int err; + + if (!test_bit(HINIC3_RSS_ENABLE, &nic_dev->flags)) { + netdev_err(netdev, "Not support to set rss parameters when rss is disable\n"); + return -EOPNOTSUPP; + } + + old_hash_type = nic_dev->rss_hash_type; + new_hash_type = old_hash_type; + + switch (rxfh->hfunc) { + case ETH_RSS_HASH_NO_CHANGE: + break; + case ETH_RSS_HASH_XOR: + new_hash_type = HINIC3_RSS_HASH_ENGINE_TYPE_XOR; + break; + case ETH_RSS_HASH_TOP: + new_hash_type = HINIC3_RSS_HASH_ENGINE_TYPE_TOEP; + break; + default: + netdev_err(netdev, "Unsupported hash func %u\n", rxfh->hfunc); + return -EOPNOTSUPP; + } + + err = hinic3_set_hw_hash_type(netdev, new_hash_type); + if (err) + return err; + + err = hinic3_set_rss_rxfh(netdev, rxfh->indir, rxfh->key); + if (err) + hinic3_set_hw_hash_type(netdev, old_hash_type); + + return err; +} diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.h b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.h index 78d82c2aca06..cf48a6449404 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.h @@ -5,10 +5,30 @@ #define _HINIC3_RSS_H_ #include +#include int hinic3_rss_init(struct net_device *netdev); void hinic3_rss_uninit(struct net_device *netdev); void hinic3_try_to_enable_rss(struct net_device *netdev); void hinic3_clear_rss_config(struct net_device *netdev); +int hinic3_get_rxnfc(struct net_device *netdev, + struct ethtool_rxnfc *cmd, u32 *rule_locs); +int hinic3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd); + +void hinic3_get_channels(struct net_device *netdev, + struct ethtool_channels *channels); +int hinic3_set_channels(struct net_device *netdev, + struct ethtool_channels *channels); + +u32 hinic3_get_rxfh_indir_size(struct net_device *netdev); +u32 hinic3_get_rxfh_key_size(struct net_device *netdev); + +u32 hinic3_get_rx_ring_count(struct net_device *netdev); +int hinic3_get_rxfh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh); +int hinic3_set_rxfh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack); + #endif -- 2.54.0