1// SPDX-License-Identifier: GPL-2.0+
2// Copyright (c) 2021-2021 Hisilicon Limited.
3#include <linux/skbuff.h>
4
5#include "hnae3.h"
6#include "hclge_comm_cmd.h"
7#include "hclge_comm_rss.h"
8
9static const u8 hclge_comm_hash_key[] = {
10	0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
11	0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
12	0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
13	0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
14	0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
15};
16
17static void
18hclge_comm_init_rss_tuple(struct hnae3_ae_dev *ae_dev,
19			  struct hclge_comm_rss_tuple_cfg *rss_tuple_cfg)
20{
21	rss_tuple_cfg->ipv4_tcp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
22	rss_tuple_cfg->ipv4_udp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
23	rss_tuple_cfg->ipv4_sctp_en = HCLGE_COMM_RSS_INPUT_TUPLE_SCTP;
24	rss_tuple_cfg->ipv4_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
25	rss_tuple_cfg->ipv6_tcp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
26	rss_tuple_cfg->ipv6_udp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
27	rss_tuple_cfg->ipv6_sctp_en =
28		ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2 ?
29		HCLGE_COMM_RSS_INPUT_TUPLE_SCTP_NO_PORT :
30		HCLGE_COMM_RSS_INPUT_TUPLE_SCTP;
31	rss_tuple_cfg->ipv6_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
32}
33
34int hclge_comm_rss_init_cfg(struct hnae3_handle *nic,
35			    struct hnae3_ae_dev *ae_dev,
36			    struct hclge_comm_rss_cfg *rss_cfg)
37{
38	u16 rss_ind_tbl_size = ae_dev->dev_specs.rss_ind_tbl_size;
39	int rss_algo = HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ;
40	u16 *rss_ind_tbl;
41
42	if (nic->flags & HNAE3_SUPPORT_VF)
43		rss_cfg->rss_size = nic->kinfo.rss_size;
44
45	if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
46		rss_algo = HCLGE_COMM_RSS_HASH_ALGO_SIMPLE;
47
48	hclge_comm_init_rss_tuple(ae_dev, &rss_cfg->rss_tuple_sets);
49
50	rss_cfg->rss_algo = rss_algo;
51
52	rss_ind_tbl = devm_kcalloc(&ae_dev->pdev->dev, rss_ind_tbl_size,
53				   sizeof(*rss_ind_tbl), GFP_KERNEL);
54	if (!rss_ind_tbl)
55		return -ENOMEM;
56
57	rss_cfg->rss_indirection_tbl = rss_ind_tbl;
58	memcpy(rss_cfg->rss_hash_key, hclge_comm_hash_key,
59	       HCLGE_COMM_RSS_KEY_SIZE);
60
61	hclge_comm_rss_indir_init_cfg(ae_dev, rss_cfg);
62
63	return 0;
64}
65
66void hclge_comm_get_rss_tc_info(u16 rss_size, u8 hw_tc_map, u16 *tc_offset,
67				u16 *tc_valid, u16 *tc_size)
68{
69	u16 roundup_size;
70	u32 i;
71
72	roundup_size = roundup_pow_of_two(rss_size);
73	roundup_size = ilog2(roundup_size);
74
75	for (i = 0; i < HCLGE_COMM_MAX_TC_NUM; i++) {
76		tc_valid[i] = 1;
77		tc_size[i] = roundup_size;
78		tc_offset[i] = (hw_tc_map & BIT(i)) ? rss_size * i : 0;
79	}
80}
81
82int hclge_comm_set_rss_tc_mode(struct hclge_comm_hw *hw, u16 *tc_offset,
83			       u16 *tc_valid, u16 *tc_size)
84{
85	struct hclge_comm_rss_tc_mode_cmd *req;
86	struct hclge_desc desc;
87	unsigned int i;
88	int ret;
89
90	req = (struct hclge_comm_rss_tc_mode_cmd *)desc.data;
91
92	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_TC_MODE, false);
93	for (i = 0; i < HCLGE_COMM_MAX_TC_NUM; i++) {
94		u16 mode = 0;
95
96		hnae3_set_bit(mode, HCLGE_COMM_RSS_TC_VALID_B,
97			      (tc_valid[i] & 0x1));
98		hnae3_set_field(mode, HCLGE_COMM_RSS_TC_SIZE_M,
99				HCLGE_COMM_RSS_TC_SIZE_S, tc_size[i]);
100		hnae3_set_bit(mode, HCLGE_COMM_RSS_TC_SIZE_MSB_B,
101			      tc_size[i] >> HCLGE_COMM_RSS_TC_SIZE_MSB_OFFSET &
102			      0x1);
103		hnae3_set_field(mode, HCLGE_COMM_RSS_TC_OFFSET_M,
104				HCLGE_COMM_RSS_TC_OFFSET_S, tc_offset[i]);
105
106		req->rss_tc_mode[i] = cpu_to_le16(mode);
107	}
108
109	ret = hclge_comm_cmd_send(hw, &desc, 1);
110	if (ret)
111		dev_err(&hw->cmq.csq.pdev->dev,
112			"failed to set rss tc mode, ret = %d.\n", ret);
113
114	return ret;
115}
116
117int hclge_comm_set_rss_hash_key(struct hclge_comm_rss_cfg *rss_cfg,
118				struct hclge_comm_hw *hw, const u8 *key,
119				const u8 hfunc)
120{
121	u8 hash_algo;
122	int ret;
123
124	ret = hclge_comm_parse_rss_hfunc(rss_cfg, hfunc, &hash_algo);
125	if (ret)
126		return ret;
127
128	/* Set the RSS Hash Key if specififed by the user */
129	if (key) {
130		ret = hclge_comm_set_rss_algo_key(hw, hash_algo, key);
131		if (ret)
132			return ret;
133
134		/* Update the shadow RSS key with user specified qids */
135		memcpy(rss_cfg->rss_hash_key, key, HCLGE_COMM_RSS_KEY_SIZE);
136	} else {
137		ret = hclge_comm_set_rss_algo_key(hw, hash_algo,
138						  rss_cfg->rss_hash_key);
139		if (ret)
140			return ret;
141	}
142	rss_cfg->rss_algo = hash_algo;
143
144	return 0;
145}
146
147int hclge_comm_set_rss_tuple(struct hnae3_ae_dev *ae_dev,
148			     struct hclge_comm_hw *hw,
149			     struct hclge_comm_rss_cfg *rss_cfg,
150			     struct ethtool_rxnfc *nfc)
151{
152	struct hclge_comm_rss_input_tuple_cmd *req;
153	struct hclge_desc desc;
154	int ret;
155
156	if (nfc->data &
157	    ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3))
158		return -EINVAL;
159
160	req = (struct hclge_comm_rss_input_tuple_cmd *)desc.data;
161	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE,
162					false);
163
164	ret = hclge_comm_init_rss_tuple_cmd(rss_cfg, nfc, ae_dev, req);
165	if (ret) {
166		dev_err(&hw->cmq.csq.pdev->dev,
167			"failed to init rss tuple cmd, ret = %d.\n", ret);
168		return ret;
169	}
170
171	ret = hclge_comm_cmd_send(hw, &desc, 1);
172	if (ret) {
173		dev_err(&hw->cmq.csq.pdev->dev,
174			"failed to set rss tuple, ret = %d.\n", ret);
175		return ret;
176	}
177
178	rss_cfg->rss_tuple_sets.ipv4_tcp_en = req->ipv4_tcp_en;
179	rss_cfg->rss_tuple_sets.ipv4_udp_en = req->ipv4_udp_en;
180	rss_cfg->rss_tuple_sets.ipv4_sctp_en = req->ipv4_sctp_en;
181	rss_cfg->rss_tuple_sets.ipv4_fragment_en = req->ipv4_fragment_en;
182	rss_cfg->rss_tuple_sets.ipv6_tcp_en = req->ipv6_tcp_en;
183	rss_cfg->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en;
184	rss_cfg->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en;
185	rss_cfg->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en;
186	return 0;
187}
188
189u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle)
190{
191	return HCLGE_COMM_RSS_KEY_SIZE;
192}
193
194int hclge_comm_parse_rss_hfunc(struct hclge_comm_rss_cfg *rss_cfg,
195			       const u8 hfunc, u8 *hash_algo)
196{
197	switch (hfunc) {
198	case ETH_RSS_HASH_TOP:
199		*hash_algo = HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ;
200		return 0;
201	case ETH_RSS_HASH_XOR:
202		*hash_algo = HCLGE_COMM_RSS_HASH_ALGO_SIMPLE;
203		return 0;
204	case ETH_RSS_HASH_NO_CHANGE:
205		*hash_algo = rss_cfg->rss_algo;
206		return 0;
207	default:
208		return -EINVAL;
209	}
210}
211
212void hclge_comm_rss_indir_init_cfg(struct hnae3_ae_dev *ae_dev,
213				   struct hclge_comm_rss_cfg *rss_cfg)
214{
215	u16 i;
216	/* Initialize RSS indirect table */
217	for (i = 0; i < ae_dev->dev_specs.rss_ind_tbl_size; i++)
218		rss_cfg->rss_indirection_tbl[i] = i % rss_cfg->rss_size;
219}
220
221int hclge_comm_get_rss_tuple(struct hclge_comm_rss_cfg *rss_cfg, int flow_type,
222			     u8 *tuple_sets)
223{
224	switch (flow_type) {
225	case TCP_V4_FLOW:
226		*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
227		break;
228	case UDP_V4_FLOW:
229		*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_udp_en;
230		break;
231	case TCP_V6_FLOW:
232		*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
233		break;
234	case UDP_V6_FLOW:
235		*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_udp_en;
236		break;
237	case SCTP_V4_FLOW:
238		*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
239		break;
240	case SCTP_V6_FLOW:
241		*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
242		break;
243	case IPV4_FLOW:
244	case IPV6_FLOW:
245		*tuple_sets = HCLGE_COMM_S_IP_BIT | HCLGE_COMM_D_IP_BIT;
246		break;
247	default:
248		return -EINVAL;
249	}
250
251	return 0;
252}
253
254static void
255hclge_comm_append_rss_msb_info(struct hclge_comm_rss_ind_tbl_cmd *req,
256			       u16 qid, u32 j)
257{
258	u8 rss_msb_oft;
259	u8 rss_msb_val;
260
261	rss_msb_oft =
262		j * HCLGE_COMM_RSS_CFG_TBL_BW_H / BITS_PER_BYTE;
263	rss_msb_val = (qid >> HCLGE_COMM_RSS_CFG_TBL_BW_L & 0x1) <<
264		(j * HCLGE_COMM_RSS_CFG_TBL_BW_H % BITS_PER_BYTE);
265	req->rss_qid_h[rss_msb_oft] |= rss_msb_val;
266}
267
268int hclge_comm_set_rss_indir_table(struct hnae3_ae_dev *ae_dev,
269				   struct hclge_comm_hw *hw, const u16 *indir)
270{
271	struct hclge_comm_rss_ind_tbl_cmd *req;
272	struct hclge_desc desc;
273	u16 rss_cfg_tbl_num;
274	int ret;
275	u16 qid;
276	u16 i;
277	u32 j;
278
279	req = (struct hclge_comm_rss_ind_tbl_cmd *)desc.data;
280	rss_cfg_tbl_num = ae_dev->dev_specs.rss_ind_tbl_size /
281			  HCLGE_COMM_RSS_CFG_TBL_SIZE;
282
283	for (i = 0; i < rss_cfg_tbl_num; i++) {
284		hclge_comm_cmd_setup_basic_desc(&desc,
285						HCLGE_OPC_RSS_INDIR_TABLE,
286						false);
287
288		req->start_table_index =
289			cpu_to_le16(i * HCLGE_COMM_RSS_CFG_TBL_SIZE);
290		req->rss_set_bitmap =
291			cpu_to_le16(HCLGE_COMM_RSS_SET_BITMAP_MSK);
292		for (j = 0; j < HCLGE_COMM_RSS_CFG_TBL_SIZE; j++) {
293			qid = indir[i * HCLGE_COMM_RSS_CFG_TBL_SIZE + j];
294			req->rss_qid_l[j] = qid & 0xff;
295			hclge_comm_append_rss_msb_info(req, qid, j);
296		}
297		ret = hclge_comm_cmd_send(hw, &desc, 1);
298		if (ret) {
299			dev_err(&hw->cmq.csq.pdev->dev,
300				"failed to configure rss table, ret = %d.\n",
301				ret);
302			return ret;
303		}
304	}
305	return 0;
306}
307
308int hclge_comm_set_rss_input_tuple(struct hclge_comm_hw *hw,
309				   struct hclge_comm_rss_cfg *rss_cfg)
310{
311	struct hclge_comm_rss_input_tuple_cmd *req;
312	struct hclge_desc desc;
313	int ret;
314
315	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE,
316					false);
317
318	req = (struct hclge_comm_rss_input_tuple_cmd *)desc.data;
319
320	req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
321	req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
322	req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
323	req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
324	req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
325	req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
326	req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
327	req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
328
329	ret = hclge_comm_cmd_send(hw, &desc, 1);
330	if (ret)
331		dev_err(&hw->cmq.csq.pdev->dev,
332			"failed to configure rss input, ret = %d.\n", ret);
333	return ret;
334}
335
336void hclge_comm_get_rss_hash_info(struct hclge_comm_rss_cfg *rss_cfg, u8 *key,
337				  u8 *hfunc)
338{
339	/* Get hash algorithm */
340	if (hfunc) {
341		switch (rss_cfg->rss_algo) {
342		case HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ:
343			*hfunc = ETH_RSS_HASH_TOP;
344			break;
345		case HCLGE_COMM_RSS_HASH_ALGO_SIMPLE:
346			*hfunc = ETH_RSS_HASH_XOR;
347			break;
348		default:
349			*hfunc = ETH_RSS_HASH_UNKNOWN;
350			break;
351		}
352	}
353
354	/* Get the RSS Key required by the user */
355	if (key)
356		memcpy(key, rss_cfg->rss_hash_key, HCLGE_COMM_RSS_KEY_SIZE);
357}
358
359void hclge_comm_get_rss_indir_tbl(struct hclge_comm_rss_cfg *rss_cfg,
360				  u32 *indir, u16 rss_ind_tbl_size)
361{
362	u16 i;
363
364	if (!indir)
365		return;
366
367	for (i = 0; i < rss_ind_tbl_size; i++)
368		indir[i] = rss_cfg->rss_indirection_tbl[i];
369}
370
371int hclge_comm_set_rss_algo_key(struct hclge_comm_hw *hw, const u8 hfunc,
372				const u8 *key)
373{
374	struct hclge_comm_rss_config_cmd *req;
375	unsigned int key_offset = 0;
376	struct hclge_desc desc;
377	int key_counts;
378	int key_size;
379	int ret;
380
381	key_counts = HCLGE_COMM_RSS_KEY_SIZE;
382	req = (struct hclge_comm_rss_config_cmd *)desc.data;
383
384	while (key_counts) {
385		hclge_comm_cmd_setup_basic_desc(&desc,
386						HCLGE_OPC_RSS_GENERIC_CONFIG,
387						false);
388
389		req->hash_config |= (hfunc & HCLGE_COMM_RSS_HASH_ALGO_MASK);
390		req->hash_config |=
391			(key_offset << HCLGE_COMM_RSS_HASH_KEY_OFFSET_B);
392
393		key_size = min(HCLGE_COMM_RSS_HASH_KEY_NUM, key_counts);
394		memcpy(req->hash_key,
395		       key + key_offset * HCLGE_COMM_RSS_HASH_KEY_NUM,
396		       key_size);
397
398		key_counts -= key_size;
399		key_offset++;
400		ret = hclge_comm_cmd_send(hw, &desc, 1);
401		if (ret) {
402			dev_err(&hw->cmq.csq.pdev->dev,
403				"failed to configure RSS key, ret = %d.\n",
404				ret);
405			return ret;
406		}
407	}
408
409	return 0;
410}
411
412static u8 hclge_comm_get_rss_hash_bits(struct ethtool_rxnfc *nfc)
413{
414	u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGE_COMM_S_PORT_BIT : 0;
415
416	if (nfc->data & RXH_L4_B_2_3)
417		hash_sets |= HCLGE_COMM_D_PORT_BIT;
418	else
419		hash_sets &= ~HCLGE_COMM_D_PORT_BIT;
420
421	if (nfc->data & RXH_IP_SRC)
422		hash_sets |= HCLGE_COMM_S_IP_BIT;
423	else
424		hash_sets &= ~HCLGE_COMM_S_IP_BIT;
425
426	if (nfc->data & RXH_IP_DST)
427		hash_sets |= HCLGE_COMM_D_IP_BIT;
428	else
429		hash_sets &= ~HCLGE_COMM_D_IP_BIT;
430
431	if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW)
432		hash_sets |= HCLGE_COMM_V_TAG_BIT;
433
434	return hash_sets;
435}
436
437int hclge_comm_init_rss_tuple_cmd(struct hclge_comm_rss_cfg *rss_cfg,
438				  struct ethtool_rxnfc *nfc,
439				  struct hnae3_ae_dev *ae_dev,
440				  struct hclge_comm_rss_input_tuple_cmd *req)
441{
442	u8 tuple_sets;
443
444	req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
445	req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
446	req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
447	req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
448	req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
449	req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
450	req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
451	req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
452
453	tuple_sets = hclge_comm_get_rss_hash_bits(nfc);
454	switch (nfc->flow_type) {
455	case TCP_V4_FLOW:
456		req->ipv4_tcp_en = tuple_sets;
457		break;
458	case TCP_V6_FLOW:
459		req->ipv6_tcp_en = tuple_sets;
460		break;
461	case UDP_V4_FLOW:
462		req->ipv4_udp_en = tuple_sets;
463		break;
464	case UDP_V6_FLOW:
465		req->ipv6_udp_en = tuple_sets;
466		break;
467	case SCTP_V4_FLOW:
468		req->ipv4_sctp_en = tuple_sets;
469		break;
470	case SCTP_V6_FLOW:
471		if (ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2 &&
472		    (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)))
473			return -EINVAL;
474
475		req->ipv6_sctp_en = tuple_sets;
476		break;
477	case IPV4_FLOW:
478		req->ipv4_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
479		break;
480	case IPV6_FLOW:
481		req->ipv6_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
482		break;
483	default:
484		return -EINVAL;
485	}
486
487	return 0;
488}
489
490u64 hclge_comm_convert_rss_tuple(u8 tuple_sets)
491{
492	u64 tuple_data = 0;
493
494	if (tuple_sets & HCLGE_COMM_D_PORT_BIT)
495		tuple_data |= RXH_L4_B_2_3;
496	if (tuple_sets & HCLGE_COMM_S_PORT_BIT)
497		tuple_data |= RXH_L4_B_0_1;
498	if (tuple_sets & HCLGE_COMM_D_IP_BIT)
499		tuple_data |= RXH_IP_DST;
500	if (tuple_sets & HCLGE_COMM_S_IP_BIT)
501		tuple_data |= RXH_IP_SRC;
502
503	return tuple_data;
504}
505