File Index
Files and directories
Sign in
FILE

hinic3_rss.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
  3
  4#include <linux/ethtool.h>
  5
  6#include "hinic3_cmdq.h"
  7#include "hinic3_hwdev.h"
  8#include "hinic3_hwif.h"
  9#include "hinic3_mbox.h"
 10#include "hinic3_nic_cfg.h"
 11#include "hinic3_nic_dev.h"
 12#include "hinic3_rss.h"
 13
 14static void hinic3_fillout_indir_tbl(struct net_device *netdev, u16 *indir)
 15{
 16	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 17	u16 i, num_qps;
 18
 19	num_qps = nic_dev->q_params.num_qps;
 20	for (i = 0; i < L2NIC_RSS_INDIR_SIZE; i++)
 21		indir[i] = ethtool_rxfh_indir_default(i, num_qps);
 22}
 23
 24static int hinic3_rss_cfg(struct hinic3_hwdev *hwdev, u8 rss_en, u16 num_qps)
 25{
 26	struct mgmt_msg_params msg_params = {};
 27	struct l2nic_cmd_cfg_rss rss_cfg = {};
 28	int err;
 29
 30	rss_cfg.func_id = hinic3_global_func_id(hwdev);
 31	rss_cfg.rss_en = rss_en;
 32	rss_cfg.rq_priority_number = 0;
 33	rss_cfg.num_qps = num_qps;
 34
 35	mgmt_msg_params_init_default(&msg_params, &rss_cfg, sizeof(rss_cfg));
 36
 37	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
 38				       L2NIC_CMD_CFG_RSS, &msg_params);
 39	if (err || rss_cfg.msg_head.status) {
 40		dev_err(hwdev->dev, "Failed to set rss cfg, err: %d, status: 0x%x\n",
 41			err, rss_cfg.msg_head.status);
 42		return -EINVAL;
 43	}
 44
 45	return 0;
 46}
 47
 48static void hinic3_init_rss_parameters(struct net_device *netdev)
 49{
 50	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 51
 52	nic_dev->rss_hash_type = HINIC3_RSS_HASH_ENGINE_TYPE_XOR;
 53	nic_dev->rss_type.tcp_ipv6_ext = 1;
 54	nic_dev->rss_type.ipv6_ext = 1;
 55	nic_dev->rss_type.tcp_ipv6 = 1;
 56	nic_dev->rss_type.ipv6 = 1;
 57	nic_dev->rss_type.tcp_ipv4 = 1;
 58	nic_dev->rss_type.ipv4 = 1;
 59	nic_dev->rss_type.udp_ipv6 = 1;
 60	nic_dev->rss_type.udp_ipv4 = 1;
 61}
 62
 63static void decide_num_qps(struct net_device *netdev)
 64{
 65	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 66	unsigned int dev_cpus;
 67
 68	dev_cpus = netif_get_num_default_rss_queues();
 69	nic_dev->q_params.num_qps = min(dev_cpus, nic_dev->max_qps);
 70}
 71
 72static int alloc_rss_resource(struct net_device *netdev)
 73{
 74	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 75
 76	nic_dev->rss_hkey = kmalloc_array(L2NIC_RSS_KEY_SIZE,
 77					  sizeof(nic_dev->rss_hkey[0]),
 78					  GFP_KERNEL);
 79	if (!nic_dev->rss_hkey)
 80		return -ENOMEM;
 81
 82	netdev_rss_key_fill(nic_dev->rss_hkey, L2NIC_RSS_KEY_SIZE);
 83
 84	nic_dev->rss_indir = kcalloc(L2NIC_RSS_INDIR_SIZE, sizeof(u16),
 85				     GFP_KERNEL);
 86	if (!nic_dev->rss_indir) {
 87		kfree(nic_dev->rss_hkey);
 88		nic_dev->rss_hkey = NULL;
 89		return -ENOMEM;
 90	}
 91
 92	return 0;
 93}
 94
 95static int hinic3_rss_set_indir_tbl(struct hinic3_hwdev *hwdev,
 96				    const u16 *indir_table)
 97{
 98	struct l2nic_cmd_rss_set_indir_tbl *indir_tbl;
 99	struct hinic3_cmd_buf *cmd_buf;
100	__le64 out_param;
101	int err;
102	u32 i;
103
104	cmd_buf = hinic3_alloc_cmd_buf(hwdev);
105	if (!cmd_buf) {
106		dev_err(hwdev->dev, "Failed to allocate cmd buf\n");
107		return -ENOMEM;
108	}
109
110	cmd_buf->size = cpu_to_le16(sizeof(struct l2nic_cmd_rss_set_indir_tbl));
111	indir_tbl = cmd_buf->buf;
112	memset(indir_tbl, 0, sizeof(*indir_tbl));
113
114	for (i = 0; i < L2NIC_RSS_INDIR_SIZE; i++)
115		indir_tbl->entry[i] = cpu_to_le16(indir_table[i]);
116
117	hinic3_cmdq_buf_swab32(indir_tbl, sizeof(*indir_tbl));
118
119	err = hinic3_cmdq_direct_resp(hwdev, MGMT_MOD_L2NIC,
120				      L2NIC_UCODE_CMD_SET_RSS_INDIR_TBL,
121				      cmd_buf, &out_param);
122	if (err || out_param) {
123		dev_err(hwdev->dev, "Failed to set rss indir table\n");
124		err = -EFAULT;
125	}
126
127	hinic3_free_cmd_buf(hwdev, cmd_buf);
128
129	return err;
130}
131
132static int hinic3_set_rss_type(struct hinic3_hwdev *hwdev,
133			       struct hinic3_rss_type rss_type)
134{
135	struct l2nic_cmd_set_rss_ctx_tbl ctx_tbl = {};
136	struct mgmt_msg_params msg_params = {};
137	u32 ctx;
138	int err;
139
140	ctx_tbl.func_id = hinic3_global_func_id(hwdev);
141	ctx = L2NIC_RSS_TYPE_SET(1, VALID) |
142	      L2NIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) |
143	      L2NIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) |
144	      L2NIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) |
145	      L2NIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) |
146	      L2NIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) |
147	      L2NIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) |
148	      L2NIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) |
149	      L2NIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6);
150	ctx_tbl.context = ctx;
151
152	mgmt_msg_params_init_default(&msg_params, &ctx_tbl, sizeof(ctx_tbl));
153
154	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
155				       L2NIC_CMD_SET_RSS_CTX_TBL, &msg_params);
156
157	if (ctx_tbl.msg_head.status == MGMT_STATUS_CMD_UNSUPPORTED) {
158		return MGMT_STATUS_CMD_UNSUPPORTED;
159	} else if (err || ctx_tbl.msg_head.status) {
160		dev_err(hwdev->dev, "mgmt Failed to set rss context offload, err: %d, status: 0x%x\n",
161			err, ctx_tbl.msg_head.status);
162		return -EINVAL;
163	}
164
165	return 0;
166}
167
168static int hinic3_rss_cfg_hash_type(struct hinic3_hwdev *hwdev, u8 opcode,
169				    enum hinic3_rss_hash_type *type)
170{
171	struct l2nic_cmd_cfg_rss_engine hash_type_cmd = {};
172	struct mgmt_msg_params msg_params = {};
173	int err;
174
175	hash_type_cmd.func_id = hinic3_global_func_id(hwdev);
176	hash_type_cmd.opcode = opcode;
177
178	if (opcode == MGMT_MSG_CMD_OP_SET)
179		hash_type_cmd.hash_engine = *type;
180
181	mgmt_msg_params_init_default(&msg_params, &hash_type_cmd,
182				     sizeof(hash_type_cmd));
183
184	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
185				       L2NIC_CMD_CFG_RSS_HASH_ENGINE,
186				       &msg_params);
187	if (err || hash_type_cmd.msg_head.status) {
188		dev_err(hwdev->dev, "Failed to %s hash engine, err: %d, status: 0x%x\n",
189			opcode == MGMT_MSG_CMD_OP_SET ? "set" : "get",
190			err, hash_type_cmd.msg_head.status);
191		return -EIO;
192	}
193
194	if (opcode == MGMT_MSG_CMD_OP_GET)
195		*type = hash_type_cmd.hash_engine;
196
197	return 0;
198}
199
200static int hinic3_rss_set_hash_type(struct hinic3_hwdev *hwdev,
201				    enum hinic3_rss_hash_type type)
202{
203	return hinic3_rss_cfg_hash_type(hwdev, MGMT_MSG_CMD_OP_SET, &type);
204}
205
206static int hinic3_config_rss_hw_resource(struct net_device *netdev,
207					 u16 *indir_tbl)
208{
209	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
210	int err;
211
212	err = hinic3_rss_set_indir_tbl(nic_dev->hwdev, indir_tbl);
213	if (err)
214		return err;
215
216	err = hinic3_set_rss_type(nic_dev->hwdev, nic_dev->rss_type);
217	if (err)
218		return err;
219
220	return hinic3_rss_set_hash_type(nic_dev->hwdev, nic_dev->rss_hash_type);
221}
222
223static int hinic3_rss_cfg_hash_key(struct hinic3_hwdev *hwdev, u8 opcode,
224				   u8 *key)
225{
226	struct l2nic_cmd_cfg_rss_hash_key hash_key = {};
227	struct mgmt_msg_params msg_params = {};
228	int err;
229
230	hash_key.func_id = hinic3_global_func_id(hwdev);
231	hash_key.opcode = opcode;
232
233	if (opcode == MGMT_MSG_CMD_OP_SET)
234		memcpy(hash_key.key, key, L2NIC_RSS_KEY_SIZE);
235
236	mgmt_msg_params_init_default(&msg_params, &hash_key, sizeof(hash_key));
237
238	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
239				       L2NIC_CMD_CFG_RSS_HASH_KEY, &msg_params);
240	if (err || hash_key.msg_head.status) {
241		dev_err(hwdev->dev, "Failed to %s hash key, err: %d, status: 0x%x\n",
242			opcode == MGMT_MSG_CMD_OP_SET ? "set" : "get",
243			err, hash_key.msg_head.status);
244		return -EINVAL;
245	}
246
247	if (opcode == MGMT_MSG_CMD_OP_GET)
248		memcpy(key, hash_key.key, L2NIC_RSS_KEY_SIZE);
249
250	return 0;
251}
252
253static int hinic3_rss_set_hash_key(struct hinic3_hwdev *hwdev, u8 *key)
254{
255	return hinic3_rss_cfg_hash_key(hwdev, MGMT_MSG_CMD_OP_SET, key);
256}
257
258static int hinic3_set_hw_rss_parameters(struct net_device *netdev, u8 rss_en)
259{
260	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
261	int err;
262
263	err = hinic3_rss_set_hash_key(nic_dev->hwdev, nic_dev->rss_hkey);
264	if (err)
265		return err;
266
267	hinic3_fillout_indir_tbl(netdev, nic_dev->rss_indir);
268
269	err = hinic3_config_rss_hw_resource(netdev, nic_dev->rss_indir);
270	if (err)
271		return err;
272
273	err = hinic3_rss_cfg(nic_dev->hwdev, rss_en, nic_dev->q_params.num_qps);
274	if (err)
275		return err;
276
277	return 0;
278}
279
280int hinic3_rss_init(struct net_device *netdev)
281{
282	return hinic3_set_hw_rss_parameters(netdev, 1);
283}
284
285void hinic3_rss_uninit(struct net_device *netdev)
286{
287	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
288
289	hinic3_rss_cfg(nic_dev->hwdev, 0, 0);
290}
291
292void hinic3_clear_rss_config(struct net_device *netdev)
293{
294	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
295
296	kfree(nic_dev->rss_hkey);
297	nic_dev->rss_hkey = NULL;
298
299	kfree(nic_dev->rss_indir);
300	nic_dev->rss_indir = NULL;
301}
302
303void hinic3_try_to_enable_rss(struct net_device *netdev)
304{
305	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
306	struct hinic3_hwdev *hwdev = nic_dev->hwdev;
307	int err;
308
309	nic_dev->max_qps = hinic3_func_max_qnum(hwdev);
310	if (nic_dev->max_qps <= 1 ||
311	    !hinic3_test_support(nic_dev, HINIC3_NIC_F_RSS))
312		goto err_reset_q_params;
313
314	err = alloc_rss_resource(netdev);
315	if (err) {
316		nic_dev->max_qps = 1;
317		goto err_reset_q_params;
318	}
319
320	set_bit(HINIC3_RSS_ENABLE, &nic_dev->flags);
321	decide_num_qps(netdev);
322	hinic3_init_rss_parameters(netdev);
323	err = hinic3_set_hw_rss_parameters(netdev, 0);
324	if (err) {
325		dev_err(hwdev->dev, "Failed to set hardware rss parameters\n");
326		hinic3_clear_rss_config(netdev);
327		nic_dev->max_qps = 1;
328		goto err_reset_q_params;
329	}
330
331	return;
332
333err_reset_q_params:
334	clear_bit(HINIC3_RSS_ENABLE, &nic_dev->flags);
335	nic_dev->q_params.num_qps = nic_dev->max_qps;
336}
~/ Read-only file preview.