1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2019, Intel Corporation. */
3
4#include "ice_common.h"
5#include "ice_flow.h"
6
7/* Describe properties of a protocol header field */
8struct ice_flow_field_info {
9	enum ice_flow_seg_hdr hdr;
10	s16 off;	/* Offset from start of a protocol header, in bits */
11	u16 size;	/* Size of fields in bits */
12};
13
14#define ICE_FLOW_FLD_INFO(_hdr, _offset_bytes, _size_bytes) { \
15	.hdr = _hdr, \
16	.off = (_offset_bytes) * BITS_PER_BYTE, \
17	.size = (_size_bytes) * BITS_PER_BYTE, \
18}
19
20/* Table containing properties of supported protocol header fields */
21static const
22struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
23	/* IPv4 / IPv6 */
24	/* ICE_FLOW_FIELD_IDX_IPV4_SA */
25	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 12, sizeof(struct in_addr)),
26	/* ICE_FLOW_FIELD_IDX_IPV4_DA */
27	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 16, sizeof(struct in_addr)),
28	/* ICE_FLOW_FIELD_IDX_IPV6_SA */
29	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 8, sizeof(struct in6_addr)),
30	/* ICE_FLOW_FIELD_IDX_IPV6_DA */
31	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 24, sizeof(struct in6_addr)),
32	/* Transport */
33	/* ICE_FLOW_FIELD_IDX_TCP_SRC_PORT */
34	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 0, sizeof(__be16)),
35	/* ICE_FLOW_FIELD_IDX_TCP_DST_PORT */
36	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 2, sizeof(__be16)),
37	/* ICE_FLOW_FIELD_IDX_UDP_SRC_PORT */
38	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 0, sizeof(__be16)),
39	/* ICE_FLOW_FIELD_IDX_UDP_DST_PORT */
40	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 2, sizeof(__be16)),
41	/* ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT */
42	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 0, sizeof(__be16)),
43	/* ICE_FLOW_FIELD_IDX_SCTP_DST_PORT */
44	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 2, sizeof(__be16)),
45	/* GRE */
46	/* ICE_FLOW_FIELD_IDX_GRE_KEYID */
47	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GRE, 12,
48			  sizeof_field(struct gre_full_hdr, key)),
49};
50
51/* Bitmaps indicating relevant packet types for a particular protocol header
52 *
53 * Packet types for packets with an Outer/First/Single IPv4 header
54 */
55static const u32 ice_ptypes_ipv4_ofos[] = {
56	0x1DC00000, 0x04000800, 0x00000000, 0x00000000,
57	0x00000000, 0x00000000, 0x00000000, 0x00000000,
58	0x00000000, 0x00000000, 0x00000000, 0x00000000,
59	0x00000000, 0x00000000, 0x00000000, 0x00000000,
60	0x00000000, 0x00000000, 0x00000000, 0x00000000,
61	0x00000000, 0x00000000, 0x00000000, 0x00000000,
62	0x00000000, 0x00000000, 0x00000000, 0x00000000,
63	0x00000000, 0x00000000, 0x00000000, 0x00000000,
64};
65
66/* Packet types for packets with an Innermost/Last IPv4 header */
67static const u32 ice_ptypes_ipv4_il[] = {
68	0xE0000000, 0xB807700E, 0x80000003, 0xE01DC03B,
69	0x0000000E, 0x00000000, 0x00000000, 0x00000000,
70	0x00000000, 0x00000000, 0x00000000, 0x00000000,
71	0x00000000, 0x00000000, 0x00000000, 0x00000000,
72	0x00000000, 0x00000000, 0x00000000, 0x00000000,
73	0x00000000, 0x00000000, 0x00000000, 0x00000000,
74	0x00000000, 0x00000000, 0x00000000, 0x00000000,
75	0x00000000, 0x00000000, 0x00000000, 0x00000000,
76};
77
78/* Packet types for packets with an Outer/First/Single IPv6 header */
79static const u32 ice_ptypes_ipv6_ofos[] = {
80	0x00000000, 0x00000000, 0x77000000, 0x10002000,
81	0x00000000, 0x00000000, 0x00000000, 0x00000000,
82	0x00000000, 0x00000000, 0x00000000, 0x00000000,
83	0x00000000, 0x00000000, 0x00000000, 0x00000000,
84	0x00000000, 0x00000000, 0x00000000, 0x00000000,
85	0x00000000, 0x00000000, 0x00000000, 0x00000000,
86	0x00000000, 0x00000000, 0x00000000, 0x00000000,
87	0x00000000, 0x00000000, 0x00000000, 0x00000000,
88};
89
90/* Packet types for packets with an Innermost/Last IPv6 header */
91static const u32 ice_ptypes_ipv6_il[] = {
92	0x00000000, 0x03B80770, 0x000001DC, 0x0EE00000,
93	0x00000770, 0x00000000, 0x00000000, 0x00000000,
94	0x00000000, 0x00000000, 0x00000000, 0x00000000,
95	0x00000000, 0x00000000, 0x00000000, 0x00000000,
96	0x00000000, 0x00000000, 0x00000000, 0x00000000,
97	0x00000000, 0x00000000, 0x00000000, 0x00000000,
98	0x00000000, 0x00000000, 0x00000000, 0x00000000,
99	0x00000000, 0x00000000, 0x00000000, 0x00000000,
100};
101
102/* Packet types for packets with an Outer/First/Single IPv4 header - no L4 */
103static const u32 ice_ipv4_ofos_no_l4[] = {
104	0x10C00000, 0x04000800, 0x00000000, 0x00000000,
105	0x00000000, 0x00000000, 0x00000000, 0x00000000,
106	0x00000000, 0x00000000, 0x00000000, 0x00000000,
107	0x00000000, 0x00000000, 0x00000000, 0x00000000,
108	0x00000000, 0x00000000, 0x00000000, 0x00000000,
109	0x00000000, 0x00000000, 0x00000000, 0x00000000,
110	0x00000000, 0x00000000, 0x00000000, 0x00000000,
111	0x00000000, 0x00000000, 0x00000000, 0x00000000,
112};
113
114/* Packet types for packets with an Innermost/Last IPv4 header - no L4 */
115static const u32 ice_ipv4_il_no_l4[] = {
116	0x60000000, 0x18043008, 0x80000002, 0x6010c021,
117	0x00000008, 0x00000000, 0x00000000, 0x00000000,
118	0x00000000, 0x00000000, 0x00000000, 0x00000000,
119	0x00000000, 0x00000000, 0x00000000, 0x00000000,
120	0x00000000, 0x00000000, 0x00000000, 0x00000000,
121	0x00000000, 0x00000000, 0x00000000, 0x00000000,
122	0x00000000, 0x00000000, 0x00000000, 0x00000000,
123	0x00000000, 0x00000000, 0x00000000, 0x00000000,
124};
125
126/* Packet types for packets with an Outer/First/Single IPv6 header - no L4 */
127static const u32 ice_ipv6_ofos_no_l4[] = {
128	0x00000000, 0x00000000, 0x43000000, 0x10002000,
129	0x00000000, 0x00000000, 0x00000000, 0x00000000,
130	0x00000000, 0x00000000, 0x00000000, 0x00000000,
131	0x00000000, 0x00000000, 0x00000000, 0x00000000,
132	0x00000000, 0x00000000, 0x00000000, 0x00000000,
133	0x00000000, 0x00000000, 0x00000000, 0x00000000,
134	0x00000000, 0x00000000, 0x00000000, 0x00000000,
135	0x00000000, 0x00000000, 0x00000000, 0x00000000,
136};
137
138/* Packet types for packets with an Innermost/Last IPv6 header - no L4 */
139static const u32 ice_ipv6_il_no_l4[] = {
140	0x00000000, 0x02180430, 0x0000010c, 0x086010c0,
141	0x00000430, 0x00000000, 0x00000000, 0x00000000,
142	0x00000000, 0x00000000, 0x00000000, 0x00000000,
143	0x00000000, 0x00000000, 0x00000000, 0x00000000,
144	0x00000000, 0x00000000, 0x00000000, 0x00000000,
145	0x00000000, 0x00000000, 0x00000000, 0x00000000,
146	0x00000000, 0x00000000, 0x00000000, 0x00000000,
147	0x00000000, 0x00000000, 0x00000000, 0x00000000,
148};
149
150/* UDP Packet types for non-tunneled packets or tunneled
151 * packets with inner UDP.
152 */
153static const u32 ice_ptypes_udp_il[] = {
154	0x81000000, 0x20204040, 0x04000010, 0x80810102,
155	0x00000040, 0x00000000, 0x00000000, 0x00000000,
156	0x00000000, 0x00000000, 0x00000000, 0x00000000,
157	0x00000000, 0x00000000, 0x00000000, 0x00000000,
158	0x00000000, 0x00000000, 0x00000000, 0x00000000,
159	0x00000000, 0x00000000, 0x00000000, 0x00000000,
160	0x00000000, 0x00000000, 0x00000000, 0x00000000,
161	0x00000000, 0x00000000, 0x00000000, 0x00000000,
162};
163
164/* Packet types for packets with an Innermost/Last TCP header */
165static const u32 ice_ptypes_tcp_il[] = {
166	0x04000000, 0x80810102, 0x10000040, 0x02040408,
167	0x00000102, 0x00000000, 0x00000000, 0x00000000,
168	0x00000000, 0x00000000, 0x00000000, 0x00000000,
169	0x00000000, 0x00000000, 0x00000000, 0x00000000,
170	0x00000000, 0x00000000, 0x00000000, 0x00000000,
171	0x00000000, 0x00000000, 0x00000000, 0x00000000,
172	0x00000000, 0x00000000, 0x00000000, 0x00000000,
173	0x00000000, 0x00000000, 0x00000000, 0x00000000,
174};
175
176/* Packet types for packets with an Innermost/Last SCTP header */
177static const u32 ice_ptypes_sctp_il[] = {
178	0x08000000, 0x01020204, 0x20000081, 0x04080810,
179	0x00000204, 0x00000000, 0x00000000, 0x00000000,
180	0x00000000, 0x00000000, 0x00000000, 0x00000000,
181	0x00000000, 0x00000000, 0x00000000, 0x00000000,
182	0x00000000, 0x00000000, 0x00000000, 0x00000000,
183	0x00000000, 0x00000000, 0x00000000, 0x00000000,
184	0x00000000, 0x00000000, 0x00000000, 0x00000000,
185	0x00000000, 0x00000000, 0x00000000, 0x00000000,
186};
187
188/* Packet types for packets with an Outermost/First GRE header */
189static const u32 ice_ptypes_gre_of[] = {
190	0x00000000, 0xBFBF7800, 0x000001DF, 0xFEFDE000,
191	0x0000017E, 0x00000000, 0x00000000, 0x00000000,
192	0x00000000, 0x00000000, 0x00000000, 0x00000000,
193	0x00000000, 0x00000000, 0x00000000, 0x00000000,
194	0x00000000, 0x00000000, 0x00000000, 0x00000000,
195	0x00000000, 0x00000000, 0x00000000, 0x00000000,
196	0x00000000, 0x00000000, 0x00000000, 0x00000000,
197	0x00000000, 0x00000000, 0x00000000, 0x00000000,
198};
199
200/* Manage parameters and info. used during the creation of a flow profile */
201struct ice_flow_prof_params {
202	enum ice_block blk;
203	u16 entry_length; /* # of bytes formatted entry will require */
204	u8 es_cnt;
205	struct ice_flow_prof *prof;
206
207	/* For ACL, the es[0] will have the data of ICE_RX_MDID_PKT_FLAGS_15_0
208	 * This will give us the direction flags.
209	 */
210	struct ice_fv_word es[ICE_MAX_FV_WORDS];
211	DECLARE_BITMAP(ptypes, ICE_FLOW_PTYPE_MAX);
212};
213
214#define ICE_FLOW_SEG_HDRS_L3_MASK	\
215	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
216#define ICE_FLOW_SEG_HDRS_L4_MASK	\
217	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
218
219/**
220 * ice_flow_val_hdrs - validates packet segments for valid protocol headers
221 * @segs: array of one or more packet segments that describe the flow
222 * @segs_cnt: number of packet segments provided
223 */
224static enum ice_status
225ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
226{
227	u8 i;
228
229	for (i = 0; i < segs_cnt; i++) {
230		/* Multiple L3 headers */
231		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
232		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
233			return ICE_ERR_PARAM;
234
235		/* Multiple L4 headers */
236		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK &&
237		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK))
238			return ICE_ERR_PARAM;
239	}
240
241	return 0;
242}
243
244/* Sizes of fixed known protocol headers without header options */
245#define ICE_FLOW_PROT_HDR_SZ_MAC	14
246#define ICE_FLOW_PROT_HDR_SZ_IPV4	20
247#define ICE_FLOW_PROT_HDR_SZ_IPV6	40
248#define ICE_FLOW_PROT_HDR_SZ_TCP	20
249#define ICE_FLOW_PROT_HDR_SZ_UDP	8
250#define ICE_FLOW_PROT_HDR_SZ_SCTP	12
251
252/**
253 * ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
254 * @params: information about the flow to be processed
255 * @seg: index of packet segment whose header size is to be determined
256 */
257static u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
258{
259	u16 sz = ICE_FLOW_PROT_HDR_SZ_MAC;
260
261	/* L3 headers */
262	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
263		sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
264	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
265		sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
266
267	/* L4 headers */
268	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
269		sz += ICE_FLOW_PROT_HDR_SZ_TCP;
270	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
271		sz += ICE_FLOW_PROT_HDR_SZ_UDP;
272	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
273		sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
274
275	return sz;
276}
277
278/**
279 * ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
280 * @params: information about the flow to be processed
281 *
282 * This function identifies the packet types associated with the protocol
283 * headers being present in packet segments of the specified flow profile.
284 */
285static enum ice_status
286ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
287{
288	struct ice_flow_prof *prof;
289	u8 i;
290
291	memset(params->ptypes, 0xff, sizeof(params->ptypes));
292
293	prof = params->prof;
294
295	for (i = 0; i < params->prof->segs_cnt; i++) {
296		const unsigned long *src;
297		u32 hdrs;
298
299		hdrs = prof->segs[i].hdrs;
300
301		if ((hdrs & ICE_FLOW_SEG_HDR_IPV4) &&
302		    !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
303			src = !i ? (const unsigned long *)ice_ipv4_ofos_no_l4 :
304				(const unsigned long *)ice_ipv4_il_no_l4;
305			bitmap_and(params->ptypes, params->ptypes, src,
306				   ICE_FLOW_PTYPE_MAX);
307		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
308			src = !i ? (const unsigned long *)ice_ptypes_ipv4_ofos :
309				(const unsigned long *)ice_ptypes_ipv4_il;
310			bitmap_and(params->ptypes, params->ptypes, src,
311				   ICE_FLOW_PTYPE_MAX);
312		} else if ((hdrs & ICE_FLOW_SEG_HDR_IPV6) &&
313			   !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
314			src = !i ? (const unsigned long *)ice_ipv6_ofos_no_l4 :
315				(const unsigned long *)ice_ipv6_il_no_l4;
316			bitmap_and(params->ptypes, params->ptypes, src,
317				   ICE_FLOW_PTYPE_MAX);
318		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
319			src = !i ? (const unsigned long *)ice_ptypes_ipv6_ofos :
320				(const unsigned long *)ice_ptypes_ipv6_il;
321			bitmap_and(params->ptypes, params->ptypes, src,
322				   ICE_FLOW_PTYPE_MAX);
323		}
324
325		if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
326			src = (const unsigned long *)ice_ptypes_udp_il;
327			bitmap_and(params->ptypes, params->ptypes, src,
328				   ICE_FLOW_PTYPE_MAX);
329		} else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
330			bitmap_and(params->ptypes, params->ptypes,
331				   (const unsigned long *)ice_ptypes_tcp_il,
332				   ICE_FLOW_PTYPE_MAX);
333		} else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
334			src = (const unsigned long *)ice_ptypes_sctp_il;
335			bitmap_and(params->ptypes, params->ptypes, src,
336				   ICE_FLOW_PTYPE_MAX);
337		} else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
338			if (!i) {
339				src = (const unsigned long *)ice_ptypes_gre_of;
340				bitmap_and(params->ptypes, params->ptypes,
341					   src, ICE_FLOW_PTYPE_MAX);
342			}
343		}
344	}
345
346	return 0;
347}
348
349/**
350 * ice_flow_xtract_fld - Create an extraction sequence entry for the given field
351 * @hw: pointer to the HW struct
352 * @params: information about the flow to be processed
353 * @seg: packet segment index of the field to be extracted
354 * @fld: ID of field to be extracted
355 *
356 * This function determines the protocol ID, offset, and size of the given
357 * field. It then allocates one or more extraction sequence entries for the
358 * given field, and fill the entries with protocol ID and offset information.
359 */
360static enum ice_status
361ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
362		    u8 seg, enum ice_flow_field fld)
363{
364	enum ice_prot_id prot_id = ICE_PROT_ID_INVAL;
365	u8 fv_words = hw->blk[params->blk].es.fvw;
366	struct ice_flow_fld_info *flds;
367	u16 cnt, ese_bits, i;
368	u16 off;
369
370	flds = params->prof->segs[seg].fields;
371
372	switch (fld) {
373	case ICE_FLOW_FIELD_IDX_IPV4_SA:
374	case ICE_FLOW_FIELD_IDX_IPV4_DA:
375		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
376		break;
377	case ICE_FLOW_FIELD_IDX_IPV6_SA:
378	case ICE_FLOW_FIELD_IDX_IPV6_DA:
379		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
380		break;
381	case ICE_FLOW_FIELD_IDX_TCP_SRC_PORT:
382	case ICE_FLOW_FIELD_IDX_TCP_DST_PORT:
383		prot_id = ICE_PROT_TCP_IL;
384		break;
385	case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
386	case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
387		prot_id = ICE_PROT_UDP_IL_OR_S;
388		break;
389	case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
390	case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
391		prot_id = ICE_PROT_SCTP_IL;
392		break;
393	case ICE_FLOW_FIELD_IDX_GRE_KEYID:
394		prot_id = ICE_PROT_GRE_OF;
395		break;
396	default:
397		return ICE_ERR_NOT_IMPL;
398	}
399
400	/* Each extraction sequence entry is a word in size, and extracts a
401	 * word-aligned offset from a protocol header.
402	 */
403	ese_bits = ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE;
404
405	flds[fld].xtrct.prot_id = prot_id;
406	flds[fld].xtrct.off = (ice_flds_info[fld].off / ese_bits) *
407		ICE_FLOW_FV_EXTRACT_SZ;
408	flds[fld].xtrct.disp = (u8)(ice_flds_info[fld].off % ese_bits);
409	flds[fld].xtrct.idx = params->es_cnt;
410
411	/* Adjust the next field-entry index after accommodating the number of
412	 * entries this field consumes
413	 */
414	cnt = DIV_ROUND_UP(flds[fld].xtrct.disp + ice_flds_info[fld].size,
415			   ese_bits);
416
417	/* Fill in the extraction sequence entries needed for this field */
418	off = flds[fld].xtrct.off;
419	for (i = 0; i < cnt; i++) {
420		u8 idx;
421
422		/* Make sure the number of extraction sequence required
423		 * does not exceed the block's capability
424		 */
425		if (params->es_cnt >= fv_words)
426			return ICE_ERR_MAX_LIMIT;
427
428		/* some blocks require a reversed field vector layout */
429		if (hw->blk[params->blk].es.reverse)
430			idx = fv_words - params->es_cnt - 1;
431		else
432			idx = params->es_cnt;
433
434		params->es[idx].prot_id = prot_id;
435		params->es[idx].off = off;
436		params->es_cnt++;
437
438		off += ICE_FLOW_FV_EXTRACT_SZ;
439	}
440
441	return 0;
442}
443
444/**
445 * ice_flow_xtract_raws - Create extract sequence entries for raw bytes
446 * @hw: pointer to the HW struct
447 * @params: information about the flow to be processed
448 * @seg: index of packet segment whose raw fields are to be extracted
449 */
450static enum ice_status
451ice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
452		     u8 seg)
453{
454	u16 fv_words;
455	u16 hdrs_sz;
456	u8 i;
457
458	if (!params->prof->segs[seg].raws_cnt)
459		return 0;
460
461	if (params->prof->segs[seg].raws_cnt >
462	    ARRAY_SIZE(params->prof->segs[seg].raws))
463		return ICE_ERR_MAX_LIMIT;
464
465	/* Offsets within the segment headers are not supported */
466	hdrs_sz = ice_flow_calc_seg_sz(params, seg);
467	if (!hdrs_sz)
468		return ICE_ERR_PARAM;
469
470	fv_words = hw->blk[params->blk].es.fvw;
471
472	for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
473		struct ice_flow_seg_fld_raw *raw;
474		u16 off, cnt, j;
475
476		raw = &params->prof->segs[seg].raws[i];
477
478		/* Storing extraction information */
479		raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
480		raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
481			ICE_FLOW_FV_EXTRACT_SZ;
482		raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
483			BITS_PER_BYTE;
484		raw->info.xtrct.idx = params->es_cnt;
485
486		/* Determine the number of field vector entries this raw field
487		 * consumes.
488		 */
489		cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
490				   (raw->info.src.last * BITS_PER_BYTE),
491				   (ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
492		off = raw->info.xtrct.off;
493		for (j = 0; j < cnt; j++) {
494			u16 idx;
495
496			/* Make sure the number of extraction sequence required
497			 * does not exceed the block's capability
498			 */
499			if (params->es_cnt >= hw->blk[params->blk].es.count ||
500			    params->es_cnt >= ICE_MAX_FV_WORDS)
501				return ICE_ERR_MAX_LIMIT;
502
503			/* some blocks require a reversed field vector layout */
504			if (hw->blk[params->blk].es.reverse)
505				idx = fv_words - params->es_cnt - 1;
506			else
507				idx = params->es_cnt;
508
509			params->es[idx].prot_id = raw->info.xtrct.prot_id;
510			params->es[idx].off = off;
511			params->es_cnt++;
512			off += ICE_FLOW_FV_EXTRACT_SZ;
513		}
514	}
515
516	return 0;
517}
518
519/**
520 * ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
521 * @hw: pointer to the HW struct
522 * @params: information about the flow to be processed
523 *
524 * This function iterates through all matched fields in the given segments, and
525 * creates an extraction sequence for the fields.
526 */
527static enum ice_status
528ice_flow_create_xtrct_seq(struct ice_hw *hw,
529			  struct ice_flow_prof_params *params)
530{
531	struct ice_flow_prof *prof = params->prof;
532	enum ice_status status = 0;
533	u8 i;
534
535	for (i = 0; i < prof->segs_cnt; i++) {
536		u8 j;
537
538		for_each_set_bit(j, (unsigned long *)&prof->segs[i].match,
539				 ICE_FLOW_FIELD_IDX_MAX) {
540			status = ice_flow_xtract_fld(hw, params, i,
541						     (enum ice_flow_field)j);
542			if (status)
543				return status;
544		}
545
546		/* Process raw matching bytes */
547		status = ice_flow_xtract_raws(hw, params, i);
548		if (status)
549			return status;
550	}
551
552	return status;
553}
554
555/**
556 * ice_flow_proc_segs - process all packet segments associated with a profile
557 * @hw: pointer to the HW struct
558 * @params: information about the flow to be processed
559 */
560static enum ice_status
561ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
562{
563	enum ice_status status;
564
565	status = ice_flow_proc_seg_hdrs(params);
566	if (status)
567		return status;
568
569	status = ice_flow_create_xtrct_seq(hw, params);
570	if (status)
571		return status;
572
573	switch (params->blk) {
574	case ICE_BLK_FD:
575	case ICE_BLK_RSS:
576		status = 0;
577		break;
578	default:
579		return ICE_ERR_NOT_IMPL;
580	}
581
582	return status;
583}
584
585#define ICE_FLOW_FIND_PROF_CHK_FLDS	0x00000001
586#define ICE_FLOW_FIND_PROF_CHK_VSI	0x00000002
587#define ICE_FLOW_FIND_PROF_NOT_CHK_DIR	0x00000004
588
589/**
590 * ice_flow_find_prof_conds - Find a profile matching headers and conditions
591 * @hw: pointer to the HW struct
592 * @blk: classification stage
593 * @dir: flow direction
594 * @segs: array of one or more packet segments that describe the flow
595 * @segs_cnt: number of packet segments provided
596 * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
597 * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
598 */
599static struct ice_flow_prof *
600ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
601			 enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
602			 u8 segs_cnt, u16 vsi_handle, u32 conds)
603{
604	struct ice_flow_prof *p, *prof = NULL;
605
606	mutex_lock(&hw->fl_profs_locks[blk]);
607	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
608		if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
609		    segs_cnt && segs_cnt == p->segs_cnt) {
610			u8 i;
611
612			/* Check for profile-VSI association if specified */
613			if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) &&
614			    ice_is_vsi_valid(hw, vsi_handle) &&
615			    !test_bit(vsi_handle, p->vsis))
616				continue;
617
618			/* Protocol headers must be checked. Matched fields are
619			 * checked if specified.
620			 */
621			for (i = 0; i < segs_cnt; i++)
622				if (segs[i].hdrs != p->segs[i].hdrs ||
623				    ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) &&
624				     segs[i].match != p->segs[i].match))
625					break;
626
627			/* A match is found if all segments are matched */
628			if (i == segs_cnt) {
629				prof = p;
630				break;
631			}
632		}
633	mutex_unlock(&hw->fl_profs_locks[blk]);
634
635	return prof;
636}
637
638/**
639 * ice_flow_find_prof_id - Look up a profile with given profile ID
640 * @hw: pointer to the HW struct
641 * @blk: classification stage
642 * @prof_id: unique ID to identify this flow profile
643 */
644static struct ice_flow_prof *
645ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
646{
647	struct ice_flow_prof *p;
648
649	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
650		if (p->id == prof_id)
651			return p;
652
653	return NULL;
654}
655
656/**
657 * ice_dealloc_flow_entry - Deallocate flow entry memory
658 * @hw: pointer to the HW struct
659 * @entry: flow entry to be removed
660 */
661static void
662ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)
663{
664	if (!entry)
665		return;
666
667	if (entry->entry)
668		devm_kfree(ice_hw_to_dev(hw), entry->entry);
669
670	devm_kfree(ice_hw_to_dev(hw), entry);
671}
672
673/**
674 * ice_flow_rem_entry_sync - Remove a flow entry
675 * @hw: pointer to the HW struct
676 * @blk: classification stage
677 * @entry: flow entry to be removed
678 */
679static enum ice_status
680ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
681			struct ice_flow_entry *entry)
682{
683	if (!entry)
684		return ICE_ERR_BAD_PTR;
685
686	list_del(&entry->l_entry);
687
688	ice_dealloc_flow_entry(hw, entry);
689
690	return 0;
691}
692
693/**
694 * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields
695 * @hw: pointer to the HW struct
696 * @blk: classification stage
697 * @dir: flow direction
698 * @prof_id: unique ID to identify this flow profile
699 * @segs: array of one or more packet segments that describe the flow
700 * @segs_cnt: number of packet segments provided
701 * @prof: stores the returned flow profile added
702 *
703 * Assumption: the caller has acquired the lock to the profile list
704 */
705static enum ice_status
706ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
707		       enum ice_flow_dir dir, u64 prof_id,
708		       struct ice_flow_seg_info *segs, u8 segs_cnt,
709		       struct ice_flow_prof **prof)
710{
711	struct ice_flow_prof_params params;
712	enum ice_status status;
713	u8 i;
714
715	if (!prof)
716		return ICE_ERR_BAD_PTR;
717
718	memset(&params, 0, sizeof(params));
719	params.prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*params.prof),
720				   GFP_KERNEL);
721	if (!params.prof)
722		return ICE_ERR_NO_MEMORY;
723
724	/* initialize extraction sequence to all invalid (0xff) */
725	for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
726		params.es[i].prot_id = ICE_PROT_INVALID;
727		params.es[i].off = ICE_FV_OFFSET_INVAL;
728	}
729
730	params.blk = blk;
731	params.prof->id = prof_id;
732	params.prof->dir = dir;
733	params.prof->segs_cnt = segs_cnt;
734
735	/* Make a copy of the segments that need to be persistent in the flow
736	 * profile instance
737	 */
738	for (i = 0; i < segs_cnt; i++)
739		memcpy(&params.prof->segs[i], &segs[i], sizeof(*segs));
740
741	status = ice_flow_proc_segs(hw, &params);
742	if (status) {
743		ice_debug(hw, ICE_DBG_FLOW,
744			  "Error processing a flow's packet segments\n");
745		goto out;
746	}
747
748	/* Add a HW profile for this flow profile */
749	status = ice_add_prof(hw, blk, prof_id, (u8 *)params.ptypes, params.es);
750	if (status) {
751		ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
752		goto out;
753	}
754
755	INIT_LIST_HEAD(&params.prof->entries);
756	mutex_init(&params.prof->entries_lock);
757	*prof = params.prof;
758
759out:
760	if (status)
761		devm_kfree(ice_hw_to_dev(hw), params.prof);
762
763	return status;
764}
765
766/**
767 * ice_flow_rem_prof_sync - remove a flow profile
768 * @hw: pointer to the hardware structure
769 * @blk: classification stage
770 * @prof: pointer to flow profile to remove
771 *
772 * Assumption: the caller has acquired the lock to the profile list
773 */
774static enum ice_status
775ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
776		       struct ice_flow_prof *prof)
777{
778	enum ice_status status;
779
780	/* Remove all remaining flow entries before removing the flow profile */
781	if (!list_empty(&prof->entries)) {
782		struct ice_flow_entry *e, *t;
783
784		mutex_lock(&prof->entries_lock);
785
786		list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
787			status = ice_flow_rem_entry_sync(hw, blk, e);
788			if (status)
789				break;
790		}
791
792		mutex_unlock(&prof->entries_lock);
793	}
794
795	/* Remove all hardware profiles associated with this flow profile */
796	status = ice_rem_prof(hw, blk, prof->id);
797	if (!status) {
798		list_del(&prof->l_entry);
799		mutex_destroy(&prof->entries_lock);
800		devm_kfree(ice_hw_to_dev(hw), prof);
801	}
802
803	return status;
804}
805
806/**
807 * ice_flow_assoc_prof - associate a VSI with a flow profile
808 * @hw: pointer to the hardware structure
809 * @blk: classification stage
810 * @prof: pointer to flow profile
811 * @vsi_handle: software VSI handle
812 *
813 * Assumption: the caller has acquired the lock to the profile list
814 * and the software VSI handle has been validated
815 */
816static enum ice_status
817ice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,
818		    struct ice_flow_prof *prof, u16 vsi_handle)
819{
820	enum ice_status status = 0;
821
822	if (!test_bit(vsi_handle, prof->vsis)) {
823		status = ice_add_prof_id_flow(hw, blk,
824					      ice_get_hw_vsi_num(hw,
825								 vsi_handle),
826					      prof->id);
827		if (!status)
828			set_bit(vsi_handle, prof->vsis);
829		else
830			ice_debug(hw, ICE_DBG_FLOW,
831				  "HW profile add failed, %d\n",
832				  status);
833	}
834
835	return status;
836}
837
838/**
839 * ice_flow_disassoc_prof - disassociate a VSI from a flow profile
840 * @hw: pointer to the hardware structure
841 * @blk: classification stage
842 * @prof: pointer to flow profile
843 * @vsi_handle: software VSI handle
844 *
845 * Assumption: the caller has acquired the lock to the profile list
846 * and the software VSI handle has been validated
847 */
848static enum ice_status
849ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
850		       struct ice_flow_prof *prof, u16 vsi_handle)
851{
852	enum ice_status status = 0;
853
854	if (test_bit(vsi_handle, prof->vsis)) {
855		status = ice_rem_prof_id_flow(hw, blk,
856					      ice_get_hw_vsi_num(hw,
857								 vsi_handle),
858					      prof->id);
859		if (!status)
860			clear_bit(vsi_handle, prof->vsis);
861		else
862			ice_debug(hw, ICE_DBG_FLOW,
863				  "HW profile remove failed, %d\n",
864				  status);
865	}
866
867	return status;
868}
869
870/**
871 * ice_flow_add_prof - Add a flow profile for packet segments and matched fields
872 * @hw: pointer to the HW struct
873 * @blk: classification stage
874 * @dir: flow direction
875 * @prof_id: unique ID to identify this flow profile
876 * @segs: array of one or more packet segments that describe the flow
877 * @segs_cnt: number of packet segments provided
878 * @prof: stores the returned flow profile added
879 */
880enum ice_status
881ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
882		  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
883		  struct ice_flow_prof **prof)
884{
885	enum ice_status status;
886
887	if (segs_cnt > ICE_FLOW_SEG_MAX)
888		return ICE_ERR_MAX_LIMIT;
889
890	if (!segs_cnt)
891		return ICE_ERR_PARAM;
892
893	if (!segs)
894		return ICE_ERR_BAD_PTR;
895
896	status = ice_flow_val_hdrs(segs, segs_cnt);
897	if (status)
898		return status;
899
900	mutex_lock(&hw->fl_profs_locks[blk]);
901
902	status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
903					prof);
904	if (!status)
905		list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
906
907	mutex_unlock(&hw->fl_profs_locks[blk]);
908
909	return status;
910}
911
912/**
913 * ice_flow_rem_prof - Remove a flow profile and all entries associated with it
914 * @hw: pointer to the HW struct
915 * @blk: the block for which the flow profile is to be removed
916 * @prof_id: unique ID of the flow profile to be removed
917 */
918enum ice_status
919ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
920{
921	struct ice_flow_prof *prof;
922	enum ice_status status;
923
924	mutex_lock(&hw->fl_profs_locks[blk]);
925
926	prof = ice_flow_find_prof_id(hw, blk, prof_id);
927	if (!prof) {
928		status = ICE_ERR_DOES_NOT_EXIST;
929		goto out;
930	}
931
932	/* prof becomes invalid after the call */
933	status = ice_flow_rem_prof_sync(hw, blk, prof);
934
935out:
936	mutex_unlock(&hw->fl_profs_locks[blk]);
937
938	return status;
939}
940
941/**
942 * ice_flow_add_entry - Add a flow entry
943 * @hw: pointer to the HW struct
944 * @blk: classification stage
945 * @prof_id: ID of the profile to add a new flow entry to
946 * @entry_id: unique ID to identify this flow entry
947 * @vsi_handle: software VSI handle for the flow entry
948 * @prio: priority of the flow entry
949 * @data: pointer to a data buffer containing flow entry's match values/masks
950 * @entry_h: pointer to buffer that receives the new flow entry's handle
951 */
952enum ice_status
953ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
954		   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,
955		   void *data, u64 *entry_h)
956{
957	struct ice_flow_entry *e = NULL;
958	struct ice_flow_prof *prof;
959	enum ice_status status;
960
961	/* No flow entry data is expected for RSS */
962	if (!entry_h || (!data && blk != ICE_BLK_RSS))
963		return ICE_ERR_BAD_PTR;
964
965	if (!ice_is_vsi_valid(hw, vsi_handle))
966		return ICE_ERR_PARAM;
967
968	mutex_lock(&hw->fl_profs_locks[blk]);
969
970	prof = ice_flow_find_prof_id(hw, blk, prof_id);
971	if (!prof) {
972		status = ICE_ERR_DOES_NOT_EXIST;
973	} else {
974		/* Allocate memory for the entry being added and associate
975		 * the VSI to the found flow profile
976		 */
977		e = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);
978		if (!e)
979			status = ICE_ERR_NO_MEMORY;
980		else
981			status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
982	}
983
984	mutex_unlock(&hw->fl_profs_locks[blk]);
985	if (status)
986		goto out;
987
988	e->id = entry_id;
989	e->vsi_handle = vsi_handle;
990	e->prof = prof;
991	e->priority = prio;
992
993	switch (blk) {
994	case ICE_BLK_FD:
995	case ICE_BLK_RSS:
996		break;
997	default:
998		status = ICE_ERR_NOT_IMPL;
999		goto out;
1000	}
1001
1002	mutex_lock(&prof->entries_lock);
1003	list_add(&e->l_entry, &prof->entries);
1004	mutex_unlock(&prof->entries_lock);
1005
1006	*entry_h = ICE_FLOW_ENTRY_HNDL(e);
1007
1008out:
1009	if (status && e) {
1010		if (e->entry)
1011			devm_kfree(ice_hw_to_dev(hw), e->entry);
1012		devm_kfree(ice_hw_to_dev(hw), e);
1013	}
1014
1015	return status;
1016}
1017
1018/**
1019 * ice_flow_rem_entry - Remove a flow entry
1020 * @hw: pointer to the HW struct
1021 * @blk: classification stage
1022 * @entry_h: handle to the flow entry to be removed
1023 */
1024enum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,
1025				   u64 entry_h)
1026{
1027	struct ice_flow_entry *entry;
1028	struct ice_flow_prof *prof;
1029	enum ice_status status = 0;
1030
1031	if (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)
1032		return ICE_ERR_PARAM;
1033
1034	entry = ICE_FLOW_ENTRY_PTR(entry_h);
1035
1036	/* Retain the pointer to the flow profile as the entry will be freed */
1037	prof = entry->prof;
1038
1039	if (prof) {
1040		mutex_lock(&prof->entries_lock);
1041		status = ice_flow_rem_entry_sync(hw, blk, entry);
1042		mutex_unlock(&prof->entries_lock);
1043	}
1044
1045	return status;
1046}
1047
1048/**
1049 * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
1050 * @seg: packet segment the field being set belongs to
1051 * @fld: field to be set
1052 * @field_type: type of the field
1053 * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1054 *           entry's input buffer
1055 * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1056 *            input buffer
1057 * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1058 *            entry's input buffer
1059 *
1060 * This helper function stores information of a field being matched, including
1061 * the type of the field and the locations of the value to match, the mask, and
1062 * the upper-bound value in the start of the input buffer for a flow entry.
1063 * This function should only be used for fixed-size data structures.
1064 *
1065 * This function also opportunistically determines the protocol headers to be
1066 * present based on the fields being set. Some fields cannot be used alone to
1067 * determine the protocol headers present. Sometimes, fields for particular
1068 * protocol headers are not matched. In those cases, the protocol headers
1069 * must be explicitly set.
1070 */
1071static void
1072ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
1073		     enum ice_flow_fld_match_type field_type, u16 val_loc,
1074		     u16 mask_loc, u16 last_loc)
1075{
1076	u64 bit = BIT_ULL(fld);
1077
1078	seg->match |= bit;
1079	if (field_type == ICE_FLOW_FLD_TYPE_RANGE)
1080		seg->range |= bit;
1081
1082	seg->fields[fld].type = field_type;
1083	seg->fields[fld].src.val = val_loc;
1084	seg->fields[fld].src.mask = mask_loc;
1085	seg->fields[fld].src.last = last_loc;
1086
1087	ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
1088}
1089
1090/**
1091 * ice_flow_set_fld - specifies locations of field from entry's input buffer
1092 * @seg: packet segment the field being set belongs to
1093 * @fld: field to be set
1094 * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1095 *           entry's input buffer
1096 * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1097 *            input buffer
1098 * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1099 *            entry's input buffer
1100 * @range: indicate if field being matched is to be in a range
1101 *
1102 * This function specifies the locations, in the form of byte offsets from the
1103 * start of the input buffer for a flow entry, from where the value to match,
1104 * the mask value, and upper value can be extracted. These locations are then
1105 * stored in the flow profile. When adding a flow entry associated with the
1106 * flow profile, these locations will be used to quickly extract the values and
1107 * create the content of a match entry. This function should only be used for
1108 * fixed-size data structures.
1109 */
1110void
1111ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
1112		 u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
1113{
1114	enum ice_flow_fld_match_type t = range ?
1115		ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;
1116
1117	ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
1118}
1119
1120/**
1121 * ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
1122 * @seg: packet segment the field being set belongs to
1123 * @off: offset of the raw field from the beginning of the segment in bytes
1124 * @len: length of the raw pattern to be matched
1125 * @val_loc: location of the value to match from entry's input buffer
1126 * @mask_loc: location of mask value from entry's input buffer
1127 *
1128 * This function specifies the offset of the raw field to be match from the
1129 * beginning of the specified packet segment, and the locations, in the form of
1130 * byte offsets from the start of the input buffer for a flow entry, from where
1131 * the value to match and the mask value to be extracted. These locations are
1132 * then stored in the flow profile. When adding flow entries to the associated
1133 * flow profile, these locations can be used to quickly extract the values to
1134 * create the content of a match entry. This function should only be used for
1135 * fixed-size data structures.
1136 */
1137void
1138ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
1139		     u16 val_loc, u16 mask_loc)
1140{
1141	if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
1142		seg->raws[seg->raws_cnt].off = off;
1143		seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
1144		seg->raws[seg->raws_cnt].info.src.val = val_loc;
1145		seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
1146		/* The "last" field is used to store the length of the field */
1147		seg->raws[seg->raws_cnt].info.src.last = len;
1148	}
1149
1150	/* Overflows of "raws" will be handled as an error condition later in
1151	 * the flow when this information is processed.
1152	 */
1153	seg->raws_cnt++;
1154}
1155
1156#define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
1157	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
1158
1159#define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
1160	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
1161
1162#define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
1163	(ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
1164	 ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
1165
1166/**
1167 * ice_flow_set_rss_seg_info - setup packet segments for RSS
1168 * @segs: pointer to the flow field segment(s)
1169 * @hash_fields: fields to be hashed on for the segment(s)
1170 * @flow_hdr: protocol header fields within a packet segment
1171 *
1172 * Helper function to extract fields from hash bitmap and use flow
1173 * header value to set flow field segment for further use in flow
1174 * profile entry or removal.
1175 */
1176static enum ice_status
1177ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
1178			  u32 flow_hdr)
1179{
1180	u64 val;
1181	u8 i;
1182
1183	for_each_set_bit(i, (unsigned long *)&hash_fields,
1184			 ICE_FLOW_FIELD_IDX_MAX)
1185		ice_flow_set_fld(segs, (enum ice_flow_field)i,
1186				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
1187				 ICE_FLOW_FLD_OFF_INVAL, false);
1188
1189	ICE_FLOW_SET_HDRS(segs, flow_hdr);
1190
1191	if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
1192		return ICE_ERR_PARAM;
1193
1194	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
1195	if (val && !is_power_of_2(val))
1196		return ICE_ERR_CFG;
1197
1198	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
1199	if (val && !is_power_of_2(val))
1200		return ICE_ERR_CFG;
1201
1202	return 0;
1203}
1204
1205/**
1206 * ice_rem_vsi_rss_list - remove VSI from RSS list
1207 * @hw: pointer to the hardware structure
1208 * @vsi_handle: software VSI handle
1209 *
1210 * Remove the VSI from all RSS configurations in the list.
1211 */
1212void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle)
1213{
1214	struct ice_rss_cfg *r, *tmp;
1215
1216	if (list_empty(&hw->rss_list_head))
1217		return;
1218
1219	mutex_lock(&hw->rss_locks);
1220	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
1221		if (test_and_clear_bit(vsi_handle, r->vsis))
1222			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
1223				list_del(&r->l_entry);
1224				devm_kfree(ice_hw_to_dev(hw), r);
1225			}
1226	mutex_unlock(&hw->rss_locks);
1227}
1228
1229/**
1230 * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI
1231 * @hw: pointer to the hardware structure
1232 * @vsi_handle: software VSI handle
1233 *
1234 * This function will iterate through all flow profiles and disassociate
1235 * the VSI from that profile. If the flow profile has no VSIs it will
1236 * be removed.
1237 */
1238enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
1239{
1240	const enum ice_block blk = ICE_BLK_RSS;
1241	struct ice_flow_prof *p, *t;
1242	enum ice_status status = 0;
1243
1244	if (!ice_is_vsi_valid(hw, vsi_handle))
1245		return ICE_ERR_PARAM;
1246
1247	if (list_empty(&hw->fl_profs[blk]))
1248		return 0;
1249
1250	mutex_lock(&hw->rss_locks);
1251	list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry)
1252		if (test_bit(vsi_handle, p->vsis)) {
1253			status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle);
1254			if (status)
1255				break;
1256
1257			if (bitmap_empty(p->vsis, ICE_MAX_VSI)) {
1258				status = ice_flow_rem_prof(hw, blk, p->id);
1259				if (status)
1260					break;
1261			}
1262		}
1263	mutex_unlock(&hw->rss_locks);
1264
1265	return status;
1266}
1267
1268/**
1269 * ice_rem_rss_list - remove RSS configuration from list
1270 * @hw: pointer to the hardware structure
1271 * @vsi_handle: software VSI handle
1272 * @prof: pointer to flow profile
1273 *
1274 * Assumption: lock has already been acquired for RSS list
1275 */
1276static void
1277ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
1278{
1279	struct ice_rss_cfg *r, *tmp;
1280
1281	/* Search for RSS hash fields associated to the VSI that match the
1282	 * hash configurations associated to the flow profile. If found
1283	 * remove from the RSS entry list of the VSI context and delete entry.
1284	 */
1285	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
1286		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
1287		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
1288			clear_bit(vsi_handle, r->vsis);
1289			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
1290				list_del(&r->l_entry);
1291				devm_kfree(ice_hw_to_dev(hw), r);
1292			}
1293			return;
1294		}
1295}
1296
1297/**
1298 * ice_add_rss_list - add RSS configuration to list
1299 * @hw: pointer to the hardware structure
1300 * @vsi_handle: software VSI handle
1301 * @prof: pointer to flow profile
1302 *
1303 * Assumption: lock has already been acquired for RSS list
1304 */
1305static enum ice_status
1306ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
1307{
1308	struct ice_rss_cfg *r, *rss_cfg;
1309
1310	list_for_each_entry(r, &hw->rss_list_head, l_entry)
1311		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
1312		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
1313			set_bit(vsi_handle, r->vsis);
1314			return 0;
1315		}
1316
1317	rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg),
1318			       GFP_KERNEL);
1319	if (!rss_cfg)
1320		return ICE_ERR_NO_MEMORY;
1321
1322	rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
1323	rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
1324	set_bit(vsi_handle, rss_cfg->vsis);
1325
1326	list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
1327
1328	return 0;
1329}
1330
1331#define ICE_FLOW_PROF_HASH_S	0
1332#define ICE_FLOW_PROF_HASH_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
1333#define ICE_FLOW_PROF_HDR_S	32
1334#define ICE_FLOW_PROF_HDR_M	(0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
1335#define ICE_FLOW_PROF_ENCAP_S	63
1336#define ICE_FLOW_PROF_ENCAP_M	(BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
1337
1338#define ICE_RSS_OUTER_HEADERS	1
1339#define ICE_RSS_INNER_HEADERS	2
1340
1341/* Flow profile ID format:
1342 * [0:31] - Packet match fields
1343 * [32:62] - Protocol header
1344 * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
1345 */
1346#define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
1347	(u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
1348	      (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
1349	      ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
1350
1351/**
1352 * ice_add_rss_cfg_sync - add an RSS configuration
1353 * @hw: pointer to the hardware structure
1354 * @vsi_handle: software VSI handle
1355 * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1356 * @addl_hdrs: protocol header fields
1357 * @segs_cnt: packet segment count
1358 *
1359 * Assumption: lock has already been acquired for RSS list
1360 */
1361static enum ice_status
1362ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1363		     u32 addl_hdrs, u8 segs_cnt)
1364{
1365	const enum ice_block blk = ICE_BLK_RSS;
1366	struct ice_flow_prof *prof = NULL;
1367	struct ice_flow_seg_info *segs;
1368	enum ice_status status;
1369
1370	if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
1371		return ICE_ERR_PARAM;
1372
1373	segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
1374	if (!segs)
1375		return ICE_ERR_NO_MEMORY;
1376
1377	/* Construct the packet segment info from the hashed fields */
1378	status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
1379					   addl_hdrs);
1380	if (status)
1381		goto exit;
1382
1383	/* Search for a flow profile that has matching headers, hash fields
1384	 * and has the input VSI associated to it. If found, no further
1385	 * operations required and exit.
1386	 */
1387	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
1388					vsi_handle,
1389					ICE_FLOW_FIND_PROF_CHK_FLDS |
1390					ICE_FLOW_FIND_PROF_CHK_VSI);
1391	if (prof)
1392		goto exit;
1393
1394	/* Check if a flow profile exists with the same protocol headers and
1395	 * associated with the input VSI. If so disassociate the VSI from
1396	 * this profile. The VSI will be added to a new profile created with
1397	 * the protocol header and new hash field configuration.
1398	 */
1399	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
1400					vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
1401	if (prof) {
1402		status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
1403		if (!status)
1404			ice_rem_rss_list(hw, vsi_handle, prof);
1405		else
1406			goto exit;
1407
1408		/* Remove profile if it has no VSIs associated */
1409		if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) {
1410			status = ice_flow_rem_prof(hw, blk, prof->id);
1411			if (status)
1412				goto exit;
1413		}
1414	}
1415
1416	/* Search for a profile that has same match fields only. If this
1417	 * exists then associate the VSI to this profile.
1418	 */
1419	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
1420					vsi_handle,
1421					ICE_FLOW_FIND_PROF_CHK_FLDS);
1422	if (prof) {
1423		status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
1424		if (!status)
1425			status = ice_add_rss_list(hw, vsi_handle, prof);
1426		goto exit;
1427	}
1428
1429	/* Create a new flow profile with generated profile and packet
1430	 * segment information.
1431	 */
1432	status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
1433				   ICE_FLOW_GEN_PROFID(hashed_flds,
1434						       segs[segs_cnt - 1].hdrs,
1435						       segs_cnt),
1436				   segs, segs_cnt, &prof);
1437	if (status)
1438		goto exit;
1439
1440	status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
1441	/* If association to a new flow profile failed then this profile can
1442	 * be removed.
1443	 */
1444	if (status) {
1445		ice_flow_rem_prof(hw, blk, prof->id);
1446		goto exit;
1447	}
1448
1449	status = ice_add_rss_list(hw, vsi_handle, prof);
1450
1451exit:
1452	kfree(segs);
1453	return status;
1454}
1455
1456/**
1457 * ice_add_rss_cfg - add an RSS configuration with specified hashed fields
1458 * @hw: pointer to the hardware structure
1459 * @vsi_handle: software VSI handle
1460 * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1461 * @addl_hdrs: protocol header fields
1462 *
1463 * This function will generate a flow profile based on fields associated with
1464 * the input fields to hash on, the flow type and use the VSI number to add
1465 * a flow entry to the profile.
1466 */
1467enum ice_status
1468ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1469		u32 addl_hdrs)
1470{
1471	enum ice_status status;
1472
1473	if (hashed_flds == ICE_HASH_INVALID ||
1474	    !ice_is_vsi_valid(hw, vsi_handle))
1475		return ICE_ERR_PARAM;
1476
1477	mutex_lock(&hw->rss_locks);
1478	status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
1479				      ICE_RSS_OUTER_HEADERS);
1480	if (!status)
1481		status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
1482					      addl_hdrs, ICE_RSS_INNER_HEADERS);
1483	mutex_unlock(&hw->rss_locks);
1484
1485	return status;
1486}
1487
1488/* Mapping of AVF hash bit fields to an L3-L4 hash combination.
1489 * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
1490 * convert its values to their appropriate flow L3, L4 values.
1491 */
1492#define ICE_FLOW_AVF_RSS_IPV4_MASKS \
1493	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \
1494	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4))
1495#define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \
1496	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \
1497	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP))
1498#define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \
1499	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \
1500	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \
1501	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP))
1502#define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \
1503	(ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \
1504	 ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP))
1505
1506#define ICE_FLOW_AVF_RSS_IPV6_MASKS \
1507	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \
1508	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6))
1509#define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \
1510	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
1511	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \
1512	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP))
1513#define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \
1514	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \
1515	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP))
1516#define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \
1517	(ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \
1518	 ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP))
1519
1520/**
1521 * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
1522 * @hw: pointer to the hardware structure
1523 * @vsi_handle: software VSI handle
1524 * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
1525 *
1526 * This function will take the hash bitmap provided by the AVF driver via a
1527 * message, convert it to ICE-compatible values, and configure RSS flow
1528 * profiles.
1529 */
1530enum ice_status
1531ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
1532{
1533	enum ice_status status = 0;
1534	u64 hash_flds;
1535
1536	if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
1537	    !ice_is_vsi_valid(hw, vsi_handle))
1538		return ICE_ERR_PARAM;
1539
1540	/* Make sure no unsupported bits are specified */
1541	if (avf_hash & ~(ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS |
1542			 ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS))
1543		return ICE_ERR_CFG;
1544
1545	hash_flds = avf_hash;
1546
1547	/* Always create an L3 RSS configuration for any L4 RSS configuration */
1548	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS)
1549		hash_flds |= ICE_FLOW_AVF_RSS_IPV4_MASKS;
1550
1551	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS)
1552		hash_flds |= ICE_FLOW_AVF_RSS_IPV6_MASKS;
1553
1554	/* Create the corresponding RSS configuration for each valid hash bit */
1555	while (hash_flds) {
1556		u64 rss_hash = ICE_HASH_INVALID;
1557
1558		if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS) {
1559			if (hash_flds & ICE_FLOW_AVF_RSS_IPV4_MASKS) {
1560				rss_hash = ICE_FLOW_HASH_IPV4;
1561				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV4_MASKS;
1562			} else if (hash_flds &
1563				   ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS) {
1564				rss_hash = ICE_FLOW_HASH_IPV4 |
1565					ICE_FLOW_HASH_TCP_PORT;
1566				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS;
1567			} else if (hash_flds &
1568				   ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS) {
1569				rss_hash = ICE_FLOW_HASH_IPV4 |
1570					ICE_FLOW_HASH_UDP_PORT;
1571				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS;
1572			} else if (hash_flds &
1573				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) {
1574				rss_hash = ICE_FLOW_HASH_IPV4 |
1575					ICE_FLOW_HASH_SCTP_PORT;
1576				hash_flds &=
1577					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP);
1578			}
1579		} else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) {
1580			if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) {
1581				rss_hash = ICE_FLOW_HASH_IPV6;
1582				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV6_MASKS;
1583			} else if (hash_flds &
1584				   ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS) {
1585				rss_hash = ICE_FLOW_HASH_IPV6 |
1586					ICE_FLOW_HASH_TCP_PORT;
1587				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS;
1588			} else if (hash_flds &
1589				   ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS) {
1590				rss_hash = ICE_FLOW_HASH_IPV6 |
1591					ICE_FLOW_HASH_UDP_PORT;
1592				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS;
1593			} else if (hash_flds &
1594				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) {
1595				rss_hash = ICE_FLOW_HASH_IPV6 |
1596					ICE_FLOW_HASH_SCTP_PORT;
1597				hash_flds &=
1598					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP);
1599			}
1600		}
1601
1602		if (rss_hash == ICE_HASH_INVALID)
1603			return ICE_ERR_OUT_OF_RANGE;
1604
1605		status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
1606					 ICE_FLOW_SEG_HDR_NONE);
1607		if (status)
1608			break;
1609	}
1610
1611	return status;
1612}
1613
1614/**
1615 * ice_replay_rss_cfg - replay RSS configurations associated with VSI
1616 * @hw: pointer to the hardware structure
1617 * @vsi_handle: software VSI handle
1618 */
1619enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
1620{
1621	enum ice_status status = 0;
1622	struct ice_rss_cfg *r;
1623
1624	if (!ice_is_vsi_valid(hw, vsi_handle))
1625		return ICE_ERR_PARAM;
1626
1627	mutex_lock(&hw->rss_locks);
1628	list_for_each_entry(r, &hw->rss_list_head, l_entry) {
1629		if (test_bit(vsi_handle, r->vsis)) {
1630			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1631						      r->hashed_flds,
1632						      r->packet_hdr,
1633						      ICE_RSS_OUTER_HEADERS);
1634			if (status)
1635				break;
1636			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1637						      r->hashed_flds,
1638						      r->packet_hdr,
1639						      ICE_RSS_INNER_HEADERS);
1640			if (status)
1641				break;
1642		}
1643	}
1644	mutex_unlock(&hw->rss_locks);
1645
1646	return status;
1647}
1648
1649/**
1650 * ice_get_rss_cfg - returns hashed fields for the given header types
1651 * @hw: pointer to the hardware structure
1652 * @vsi_handle: software VSI handle
1653 * @hdrs: protocol header type
1654 *
1655 * This function will return the match fields of the first instance of flow
1656 * profile having the given header types and containing input VSI
1657 */
1658u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
1659{
1660	u64 rss_hash = ICE_HASH_INVALID;
1661	struct ice_rss_cfg *r;
1662
1663	/* verify if the protocol header is non zero and VSI is valid */
1664	if (hdrs == ICE_FLOW_SEG_HDR_NONE || !ice_is_vsi_valid(hw, vsi_handle))
1665		return ICE_HASH_INVALID;
1666
1667	mutex_lock(&hw->rss_locks);
1668	list_for_each_entry(r, &hw->rss_list_head, l_entry)
1669		if (test_bit(vsi_handle, r->vsis) &&
1670		    r->packet_hdr == hdrs) {
1671			rss_hash = r->hashed_flds;
1672			break;
1673		}
1674	mutex_unlock(&hw->rss_locks);
1675
1676	return rss_hash;
1677}
1678