xref: /freebsd/sys/dev/ice/ice_flex_pipe.c (revision 71d104536b513298902be65342afe6f3792f29e4)
1*71d10453SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2*71d10453SEric Joyner /*  Copyright (c) 2020, Intel Corporation
3*71d10453SEric Joyner  *  All rights reserved.
4*71d10453SEric Joyner  *
5*71d10453SEric Joyner  *  Redistribution and use in source and binary forms, with or without
6*71d10453SEric Joyner  *  modification, are permitted provided that the following conditions are met:
7*71d10453SEric Joyner  *
8*71d10453SEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
9*71d10453SEric Joyner  *      this list of conditions and the following disclaimer.
10*71d10453SEric Joyner  *
11*71d10453SEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
12*71d10453SEric Joyner  *      notice, this list of conditions and the following disclaimer in the
13*71d10453SEric Joyner  *      documentation and/or other materials provided with the distribution.
14*71d10453SEric Joyner  *
15*71d10453SEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
16*71d10453SEric Joyner  *      contributors may be used to endorse or promote products derived from
17*71d10453SEric Joyner  *      this software without specific prior written permission.
18*71d10453SEric Joyner  *
19*71d10453SEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*71d10453SEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*71d10453SEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*71d10453SEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23*71d10453SEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*71d10453SEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*71d10453SEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*71d10453SEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*71d10453SEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*71d10453SEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*71d10453SEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
30*71d10453SEric Joyner  */
31*71d10453SEric Joyner /*$FreeBSD$*/
32*71d10453SEric Joyner 
33*71d10453SEric Joyner #include "ice_common.h"
34*71d10453SEric Joyner #include "ice_flex_pipe.h"
35*71d10453SEric Joyner #include "ice_protocol_type.h"
36*71d10453SEric Joyner #include "ice_flow.h"
37*71d10453SEric Joyner 
38*71d10453SEric Joyner /* To support tunneling entries by PF, the package will append the PF number to
39*71d10453SEric Joyner  * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc.
40*71d10453SEric Joyner  */
41*71d10453SEric Joyner static const struct ice_tunnel_type_scan tnls[] = {
42*71d10453SEric Joyner 	{ TNL_VXLAN,		"TNL_VXLAN_PF" },
43*71d10453SEric Joyner 	{ TNL_GENEVE,		"TNL_GENEVE_PF" },
44*71d10453SEric Joyner 	{ TNL_LAST,		"" }
45*71d10453SEric Joyner };
46*71d10453SEric Joyner 
47*71d10453SEric Joyner static const u32 ice_sect_lkup[ICE_BLK_COUNT][ICE_SECT_COUNT] = {
48*71d10453SEric Joyner 	/* SWITCH */
49*71d10453SEric Joyner 	{
50*71d10453SEric Joyner 		ICE_SID_XLT0_SW,
51*71d10453SEric Joyner 		ICE_SID_XLT_KEY_BUILDER_SW,
52*71d10453SEric Joyner 		ICE_SID_XLT1_SW,
53*71d10453SEric Joyner 		ICE_SID_XLT2_SW,
54*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_SW,
55*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_SW,
56*71d10453SEric Joyner 		ICE_SID_FLD_VEC_SW,
57*71d10453SEric Joyner 		ICE_SID_CDID_KEY_BUILDER_SW,
58*71d10453SEric Joyner 		ICE_SID_CDID_REDIR_SW
59*71d10453SEric Joyner 	},
60*71d10453SEric Joyner 
61*71d10453SEric Joyner 	/* ACL */
62*71d10453SEric Joyner 	{
63*71d10453SEric Joyner 		ICE_SID_XLT0_ACL,
64*71d10453SEric Joyner 		ICE_SID_XLT_KEY_BUILDER_ACL,
65*71d10453SEric Joyner 		ICE_SID_XLT1_ACL,
66*71d10453SEric Joyner 		ICE_SID_XLT2_ACL,
67*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_ACL,
68*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_ACL,
69*71d10453SEric Joyner 		ICE_SID_FLD_VEC_ACL,
70*71d10453SEric Joyner 		ICE_SID_CDID_KEY_BUILDER_ACL,
71*71d10453SEric Joyner 		ICE_SID_CDID_REDIR_ACL
72*71d10453SEric Joyner 	},
73*71d10453SEric Joyner 
74*71d10453SEric Joyner 	/* FD */
75*71d10453SEric Joyner 	{
76*71d10453SEric Joyner 		ICE_SID_XLT0_FD,
77*71d10453SEric Joyner 		ICE_SID_XLT_KEY_BUILDER_FD,
78*71d10453SEric Joyner 		ICE_SID_XLT1_FD,
79*71d10453SEric Joyner 		ICE_SID_XLT2_FD,
80*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_FD,
81*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_FD,
82*71d10453SEric Joyner 		ICE_SID_FLD_VEC_FD,
83*71d10453SEric Joyner 		ICE_SID_CDID_KEY_BUILDER_FD,
84*71d10453SEric Joyner 		ICE_SID_CDID_REDIR_FD
85*71d10453SEric Joyner 	},
86*71d10453SEric Joyner 
87*71d10453SEric Joyner 	/* RSS */
88*71d10453SEric Joyner 	{
89*71d10453SEric Joyner 		ICE_SID_XLT0_RSS,
90*71d10453SEric Joyner 		ICE_SID_XLT_KEY_BUILDER_RSS,
91*71d10453SEric Joyner 		ICE_SID_XLT1_RSS,
92*71d10453SEric Joyner 		ICE_SID_XLT2_RSS,
93*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_RSS,
94*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_RSS,
95*71d10453SEric Joyner 		ICE_SID_FLD_VEC_RSS,
96*71d10453SEric Joyner 		ICE_SID_CDID_KEY_BUILDER_RSS,
97*71d10453SEric Joyner 		ICE_SID_CDID_REDIR_RSS
98*71d10453SEric Joyner 	},
99*71d10453SEric Joyner 
100*71d10453SEric Joyner 	/* PE */
101*71d10453SEric Joyner 	{
102*71d10453SEric Joyner 		ICE_SID_XLT0_PE,
103*71d10453SEric Joyner 		ICE_SID_XLT_KEY_BUILDER_PE,
104*71d10453SEric Joyner 		ICE_SID_XLT1_PE,
105*71d10453SEric Joyner 		ICE_SID_XLT2_PE,
106*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_PE,
107*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_PE,
108*71d10453SEric Joyner 		ICE_SID_FLD_VEC_PE,
109*71d10453SEric Joyner 		ICE_SID_CDID_KEY_BUILDER_PE,
110*71d10453SEric Joyner 		ICE_SID_CDID_REDIR_PE
111*71d10453SEric Joyner 	}
112*71d10453SEric Joyner };
113*71d10453SEric Joyner 
114*71d10453SEric Joyner /**
115*71d10453SEric Joyner  * ice_sect_id - returns section ID
116*71d10453SEric Joyner  * @blk: block type
117*71d10453SEric Joyner  * @sect: section type
118*71d10453SEric Joyner  *
119*71d10453SEric Joyner  * This helper function returns the proper section ID given a block type and a
120*71d10453SEric Joyner  * section type.
121*71d10453SEric Joyner  */
122*71d10453SEric Joyner static u32 ice_sect_id(enum ice_block blk, enum ice_sect sect)
123*71d10453SEric Joyner {
124*71d10453SEric Joyner 	return ice_sect_lkup[blk][sect];
125*71d10453SEric Joyner }
126*71d10453SEric Joyner 
127*71d10453SEric Joyner /**
128*71d10453SEric Joyner  * ice_pkg_val_buf
129*71d10453SEric Joyner  * @buf: pointer to the ice buffer
130*71d10453SEric Joyner  *
131*71d10453SEric Joyner  * This helper function validates a buffer's header.
132*71d10453SEric Joyner  */
133*71d10453SEric Joyner static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
134*71d10453SEric Joyner {
135*71d10453SEric Joyner 	struct ice_buf_hdr *hdr;
136*71d10453SEric Joyner 	u16 section_count;
137*71d10453SEric Joyner 	u16 data_end;
138*71d10453SEric Joyner 
139*71d10453SEric Joyner 	hdr = (struct ice_buf_hdr *)buf->buf;
140*71d10453SEric Joyner 	/* verify data */
141*71d10453SEric Joyner 	section_count = LE16_TO_CPU(hdr->section_count);
142*71d10453SEric Joyner 	if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT)
143*71d10453SEric Joyner 		return NULL;
144*71d10453SEric Joyner 
145*71d10453SEric Joyner 	data_end = LE16_TO_CPU(hdr->data_end);
146*71d10453SEric Joyner 	if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END)
147*71d10453SEric Joyner 		return NULL;
148*71d10453SEric Joyner 
149*71d10453SEric Joyner 	return hdr;
150*71d10453SEric Joyner }
151*71d10453SEric Joyner 
152*71d10453SEric Joyner /**
153*71d10453SEric Joyner  * ice_find_buf_table
154*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment
155*71d10453SEric Joyner  *
156*71d10453SEric Joyner  * Returns the address of the buffer table within the ice segment.
157*71d10453SEric Joyner  */
158*71d10453SEric Joyner static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg)
159*71d10453SEric Joyner {
160*71d10453SEric Joyner 	struct ice_nvm_table *nvms;
161*71d10453SEric Joyner 
162*71d10453SEric Joyner 	nvms = (struct ice_nvm_table *)
163*71d10453SEric Joyner 		(ice_seg->device_table +
164*71d10453SEric Joyner 		 LE32_TO_CPU(ice_seg->device_table_count));
165*71d10453SEric Joyner 
166*71d10453SEric Joyner 	return (_FORCE_ struct ice_buf_table *)
167*71d10453SEric Joyner 		(nvms->vers + LE32_TO_CPU(nvms->table_count));
168*71d10453SEric Joyner }
169*71d10453SEric Joyner 
170*71d10453SEric Joyner /**
171*71d10453SEric Joyner  * ice_pkg_enum_buf
172*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
173*71d10453SEric Joyner  * @state: pointer to the enum state
174*71d10453SEric Joyner  *
175*71d10453SEric Joyner  * This function will enumerate all the buffers in the ice segment. The first
176*71d10453SEric Joyner  * call is made with the ice_seg parameter non-NULL; on subsequent calls,
177*71d10453SEric Joyner  * ice_seg is set to NULL which continues the enumeration. When the function
178*71d10453SEric Joyner  * returns a NULL pointer, then the end of the buffers has been reached, or an
179*71d10453SEric Joyner  * unexpected value has been detected (for example an invalid section count or
180*71d10453SEric Joyner  * an invalid buffer end value).
181*71d10453SEric Joyner  */
182*71d10453SEric Joyner static struct ice_buf_hdr *
183*71d10453SEric Joyner ice_pkg_enum_buf(struct ice_seg *ice_seg, struct ice_pkg_enum *state)
184*71d10453SEric Joyner {
185*71d10453SEric Joyner 	if (ice_seg) {
186*71d10453SEric Joyner 		state->buf_table = ice_find_buf_table(ice_seg);
187*71d10453SEric Joyner 		if (!state->buf_table)
188*71d10453SEric Joyner 			return NULL;
189*71d10453SEric Joyner 
190*71d10453SEric Joyner 		state->buf_idx = 0;
191*71d10453SEric Joyner 		return ice_pkg_val_buf(state->buf_table->buf_array);
192*71d10453SEric Joyner 	}
193*71d10453SEric Joyner 
194*71d10453SEric Joyner 	if (++state->buf_idx < LE32_TO_CPU(state->buf_table->buf_count))
195*71d10453SEric Joyner 		return ice_pkg_val_buf(state->buf_table->buf_array +
196*71d10453SEric Joyner 				       state->buf_idx);
197*71d10453SEric Joyner 	else
198*71d10453SEric Joyner 		return NULL;
199*71d10453SEric Joyner }
200*71d10453SEric Joyner 
201*71d10453SEric Joyner /**
202*71d10453SEric Joyner  * ice_pkg_advance_sect
203*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
204*71d10453SEric Joyner  * @state: pointer to the enum state
205*71d10453SEric Joyner  *
206*71d10453SEric Joyner  * This helper function will advance the section within the ice segment,
207*71d10453SEric Joyner  * also advancing the buffer if needed.
208*71d10453SEric Joyner  */
209*71d10453SEric Joyner static bool
210*71d10453SEric Joyner ice_pkg_advance_sect(struct ice_seg *ice_seg, struct ice_pkg_enum *state)
211*71d10453SEric Joyner {
212*71d10453SEric Joyner 	if (!ice_seg && !state->buf)
213*71d10453SEric Joyner 		return false;
214*71d10453SEric Joyner 
215*71d10453SEric Joyner 	if (!ice_seg && state->buf)
216*71d10453SEric Joyner 		if (++state->sect_idx < LE16_TO_CPU(state->buf->section_count))
217*71d10453SEric Joyner 			return true;
218*71d10453SEric Joyner 
219*71d10453SEric Joyner 	state->buf = ice_pkg_enum_buf(ice_seg, state);
220*71d10453SEric Joyner 	if (!state->buf)
221*71d10453SEric Joyner 		return false;
222*71d10453SEric Joyner 
223*71d10453SEric Joyner 	/* start of new buffer, reset section index */
224*71d10453SEric Joyner 	state->sect_idx = 0;
225*71d10453SEric Joyner 	return true;
226*71d10453SEric Joyner }
227*71d10453SEric Joyner 
228*71d10453SEric Joyner /**
229*71d10453SEric Joyner  * ice_pkg_enum_section
230*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
231*71d10453SEric Joyner  * @state: pointer to the enum state
232*71d10453SEric Joyner  * @sect_type: section type to enumerate
233*71d10453SEric Joyner  *
234*71d10453SEric Joyner  * This function will enumerate all the sections of a particular type in the
235*71d10453SEric Joyner  * ice segment. The first call is made with the ice_seg parameter non-NULL;
236*71d10453SEric Joyner  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
237*71d10453SEric Joyner  * When the function returns a NULL pointer, then the end of the matching
238*71d10453SEric Joyner  * sections has been reached.
239*71d10453SEric Joyner  */
240*71d10453SEric Joyner static void *
241*71d10453SEric Joyner ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
242*71d10453SEric Joyner 		     u32 sect_type)
243*71d10453SEric Joyner {
244*71d10453SEric Joyner 	u16 offset, size;
245*71d10453SEric Joyner 
246*71d10453SEric Joyner 	if (ice_seg)
247*71d10453SEric Joyner 		state->type = sect_type;
248*71d10453SEric Joyner 
249*71d10453SEric Joyner 	if (!ice_pkg_advance_sect(ice_seg, state))
250*71d10453SEric Joyner 		return NULL;
251*71d10453SEric Joyner 
252*71d10453SEric Joyner 	/* scan for next matching section */
253*71d10453SEric Joyner 	while (state->buf->section_entry[state->sect_idx].type !=
254*71d10453SEric Joyner 	       CPU_TO_LE32(state->type))
255*71d10453SEric Joyner 		if (!ice_pkg_advance_sect(NULL, state))
256*71d10453SEric Joyner 			return NULL;
257*71d10453SEric Joyner 
258*71d10453SEric Joyner 	/* validate section */
259*71d10453SEric Joyner 	offset = LE16_TO_CPU(state->buf->section_entry[state->sect_idx].offset);
260*71d10453SEric Joyner 	if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF)
261*71d10453SEric Joyner 		return NULL;
262*71d10453SEric Joyner 
263*71d10453SEric Joyner 	size = LE16_TO_CPU(state->buf->section_entry[state->sect_idx].size);
264*71d10453SEric Joyner 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ)
265*71d10453SEric Joyner 		return NULL;
266*71d10453SEric Joyner 
267*71d10453SEric Joyner 	/* make sure the section fits in the buffer */
268*71d10453SEric Joyner 	if (offset + size > ICE_PKG_BUF_SIZE)
269*71d10453SEric Joyner 		return NULL;
270*71d10453SEric Joyner 
271*71d10453SEric Joyner 	state->sect_type =
272*71d10453SEric Joyner 		LE32_TO_CPU(state->buf->section_entry[state->sect_idx].type);
273*71d10453SEric Joyner 
274*71d10453SEric Joyner 	/* calc pointer to this section */
275*71d10453SEric Joyner 	state->sect = ((u8 *)state->buf) +
276*71d10453SEric Joyner 		LE16_TO_CPU(state->buf->section_entry[state->sect_idx].offset);
277*71d10453SEric Joyner 
278*71d10453SEric Joyner 	return state->sect;
279*71d10453SEric Joyner }
280*71d10453SEric Joyner 
281*71d10453SEric Joyner /**
282*71d10453SEric Joyner  * ice_pkg_enum_entry
283*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
284*71d10453SEric Joyner  * @state: pointer to the enum state
285*71d10453SEric Joyner  * @sect_type: section type to enumerate
286*71d10453SEric Joyner  * @offset: pointer to variable that receives the offset in the table (optional)
287*71d10453SEric Joyner  * @handler: function that handles access to the entries into the section type
288*71d10453SEric Joyner  *
289*71d10453SEric Joyner  * This function will enumerate all the entries in particular section type in
290*71d10453SEric Joyner  * the ice segment. The first call is made with the ice_seg parameter non-NULL;
291*71d10453SEric Joyner  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
292*71d10453SEric Joyner  * When the function returns a NULL pointer, then the end of the entries has
293*71d10453SEric Joyner  * been reached.
294*71d10453SEric Joyner  *
295*71d10453SEric Joyner  * Since each section may have a different header and entry size, the handler
296*71d10453SEric Joyner  * function is needed to determine the number and location entries in each
297*71d10453SEric Joyner  * section.
298*71d10453SEric Joyner  *
299*71d10453SEric Joyner  * The offset parameter is optional, but should be used for sections that
300*71d10453SEric Joyner  * contain an offset for each section table. For such cases, the section handler
301*71d10453SEric Joyner  * function must return the appropriate offset + index to give the absolution
302*71d10453SEric Joyner  * offset for each entry. For example, if the base for a section's header
303*71d10453SEric Joyner  * indicates a base offset of 10, and the index for the entry is 2, then
304*71d10453SEric Joyner  * section handler function should set the offset to 10 + 2 = 12.
305*71d10453SEric Joyner  */
306*71d10453SEric Joyner static void *
307*71d10453SEric Joyner ice_pkg_enum_entry(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
308*71d10453SEric Joyner 		   u32 sect_type, u32 *offset,
309*71d10453SEric Joyner 		   void *(*handler)(u32 sect_type, void *section,
310*71d10453SEric Joyner 				    u32 index, u32 *offset))
311*71d10453SEric Joyner {
312*71d10453SEric Joyner 	void *entry;
313*71d10453SEric Joyner 
314*71d10453SEric Joyner 	if (ice_seg) {
315*71d10453SEric Joyner 		if (!handler)
316*71d10453SEric Joyner 			return NULL;
317*71d10453SEric Joyner 
318*71d10453SEric Joyner 		if (!ice_pkg_enum_section(ice_seg, state, sect_type))
319*71d10453SEric Joyner 			return NULL;
320*71d10453SEric Joyner 
321*71d10453SEric Joyner 		state->entry_idx = 0;
322*71d10453SEric Joyner 		state->handler = handler;
323*71d10453SEric Joyner 	} else {
324*71d10453SEric Joyner 		state->entry_idx++;
325*71d10453SEric Joyner 	}
326*71d10453SEric Joyner 
327*71d10453SEric Joyner 	if (!state->handler)
328*71d10453SEric Joyner 		return NULL;
329*71d10453SEric Joyner 
330*71d10453SEric Joyner 	/* get entry */
331*71d10453SEric Joyner 	entry = state->handler(state->sect_type, state->sect, state->entry_idx,
332*71d10453SEric Joyner 			       offset);
333*71d10453SEric Joyner 	if (!entry) {
334*71d10453SEric Joyner 		/* end of a section, look for another section of this type */
335*71d10453SEric Joyner 		if (!ice_pkg_enum_section(NULL, state, 0))
336*71d10453SEric Joyner 			return NULL;
337*71d10453SEric Joyner 
338*71d10453SEric Joyner 		state->entry_idx = 0;
339*71d10453SEric Joyner 		entry = state->handler(state->sect_type, state->sect,
340*71d10453SEric Joyner 				       state->entry_idx, offset);
341*71d10453SEric Joyner 	}
342*71d10453SEric Joyner 
343*71d10453SEric Joyner 	return entry;
344*71d10453SEric Joyner }
345*71d10453SEric Joyner 
346*71d10453SEric Joyner /**
347*71d10453SEric Joyner  * ice_boost_tcam_handler
348*71d10453SEric Joyner  * @sect_type: section type
349*71d10453SEric Joyner  * @section: pointer to section
350*71d10453SEric Joyner  * @index: index of the boost TCAM entry to be returned
351*71d10453SEric Joyner  * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections
352*71d10453SEric Joyner  *
353*71d10453SEric Joyner  * This is a callback function that can be passed to ice_pkg_enum_entry.
354*71d10453SEric Joyner  * Handles enumeration of individual boost TCAM entries.
355*71d10453SEric Joyner  */
356*71d10453SEric Joyner static void *
357*71d10453SEric Joyner ice_boost_tcam_handler(u32 sect_type, void *section, u32 index, u32 *offset)
358*71d10453SEric Joyner {
359*71d10453SEric Joyner 	struct ice_boost_tcam_section *boost;
360*71d10453SEric Joyner 
361*71d10453SEric Joyner 	if (!section)
362*71d10453SEric Joyner 		return NULL;
363*71d10453SEric Joyner 
364*71d10453SEric Joyner 	if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM)
365*71d10453SEric Joyner 		return NULL;
366*71d10453SEric Joyner 
367*71d10453SEric Joyner 	if (index > ICE_MAX_BST_TCAMS_IN_BUF)
368*71d10453SEric Joyner 		return NULL;
369*71d10453SEric Joyner 
370*71d10453SEric Joyner 	if (offset)
371*71d10453SEric Joyner 		*offset = 0;
372*71d10453SEric Joyner 
373*71d10453SEric Joyner 	boost = (struct ice_boost_tcam_section *)section;
374*71d10453SEric Joyner 	if (index >= LE16_TO_CPU(boost->count))
375*71d10453SEric Joyner 		return NULL;
376*71d10453SEric Joyner 
377*71d10453SEric Joyner 	return boost->tcam + index;
378*71d10453SEric Joyner }
379*71d10453SEric Joyner 
380*71d10453SEric Joyner /**
381*71d10453SEric Joyner  * ice_find_boost_entry
382*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (non-NULL)
383*71d10453SEric Joyner  * @addr: Boost TCAM address of entry to search for
384*71d10453SEric Joyner  * @entry: returns pointer to the entry
385*71d10453SEric Joyner  *
386*71d10453SEric Joyner  * Finds a particular Boost TCAM entry and returns a pointer to that entry
387*71d10453SEric Joyner  * if it is found. The ice_seg parameter must not be NULL since the first call
388*71d10453SEric Joyner  * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure.
389*71d10453SEric Joyner  */
390*71d10453SEric Joyner static enum ice_status
391*71d10453SEric Joyner ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr,
392*71d10453SEric Joyner 		     struct ice_boost_tcam_entry **entry)
393*71d10453SEric Joyner {
394*71d10453SEric Joyner 	struct ice_boost_tcam_entry *tcam;
395*71d10453SEric Joyner 	struct ice_pkg_enum state;
396*71d10453SEric Joyner 
397*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
398*71d10453SEric Joyner 
399*71d10453SEric Joyner 	if (!ice_seg)
400*71d10453SEric Joyner 		return ICE_ERR_PARAM;
401*71d10453SEric Joyner 
402*71d10453SEric Joyner 	do {
403*71d10453SEric Joyner 		tcam = (struct ice_boost_tcam_entry *)
404*71d10453SEric Joyner 		       ice_pkg_enum_entry(ice_seg, &state,
405*71d10453SEric Joyner 					  ICE_SID_RXPARSER_BOOST_TCAM, NULL,
406*71d10453SEric Joyner 					  ice_boost_tcam_handler);
407*71d10453SEric Joyner 		if (tcam && LE16_TO_CPU(tcam->addr) == addr) {
408*71d10453SEric Joyner 			*entry = tcam;
409*71d10453SEric Joyner 			return ICE_SUCCESS;
410*71d10453SEric Joyner 		}
411*71d10453SEric Joyner 
412*71d10453SEric Joyner 		ice_seg = NULL;
413*71d10453SEric Joyner 	} while (tcam);
414*71d10453SEric Joyner 
415*71d10453SEric Joyner 	*entry = NULL;
416*71d10453SEric Joyner 	return ICE_ERR_CFG;
417*71d10453SEric Joyner }
418*71d10453SEric Joyner 
419*71d10453SEric Joyner /**
420*71d10453SEric Joyner  * ice_label_enum_handler
421*71d10453SEric Joyner  * @sect_type: section type
422*71d10453SEric Joyner  * @section: pointer to section
423*71d10453SEric Joyner  * @index: index of the label entry to be returned
424*71d10453SEric Joyner  * @offset: pointer to receive absolute offset, always zero for label sections
425*71d10453SEric Joyner  *
426*71d10453SEric Joyner  * This is a callback function that can be passed to ice_pkg_enum_entry.
427*71d10453SEric Joyner  * Handles enumeration of individual label entries.
428*71d10453SEric Joyner  */
429*71d10453SEric Joyner static void *
430*71d10453SEric Joyner ice_label_enum_handler(u32 __ALWAYS_UNUSED sect_type, void *section, u32 index,
431*71d10453SEric Joyner 		       u32 *offset)
432*71d10453SEric Joyner {
433*71d10453SEric Joyner 	struct ice_label_section *labels;
434*71d10453SEric Joyner 
435*71d10453SEric Joyner 	if (!section)
436*71d10453SEric Joyner 		return NULL;
437*71d10453SEric Joyner 
438*71d10453SEric Joyner 	if (index > ICE_MAX_LABELS_IN_BUF)
439*71d10453SEric Joyner 		return NULL;
440*71d10453SEric Joyner 
441*71d10453SEric Joyner 	if (offset)
442*71d10453SEric Joyner 		*offset = 0;
443*71d10453SEric Joyner 
444*71d10453SEric Joyner 	labels = (struct ice_label_section *)section;
445*71d10453SEric Joyner 	if (index >= LE16_TO_CPU(labels->count))
446*71d10453SEric Joyner 		return NULL;
447*71d10453SEric Joyner 
448*71d10453SEric Joyner 	return labels->label + index;
449*71d10453SEric Joyner }
450*71d10453SEric Joyner 
451*71d10453SEric Joyner /**
452*71d10453SEric Joyner  * ice_enum_labels
453*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (NULL on subsequent calls)
454*71d10453SEric Joyner  * @type: the section type that will contain the label (0 on subsequent calls)
455*71d10453SEric Joyner  * @state: ice_pkg_enum structure that will hold the state of the enumeration
456*71d10453SEric Joyner  * @value: pointer to a value that will return the label's value if found
457*71d10453SEric Joyner  *
458*71d10453SEric Joyner  * Enumerates a list of labels in the package. The caller will call
459*71d10453SEric Joyner  * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call
460*71d10453SEric Joyner  * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL
461*71d10453SEric Joyner  * the end of the list has been reached.
462*71d10453SEric Joyner  */
463*71d10453SEric Joyner static char *
464*71d10453SEric Joyner ice_enum_labels(struct ice_seg *ice_seg, u32 type, struct ice_pkg_enum *state,
465*71d10453SEric Joyner 		u16 *value)
466*71d10453SEric Joyner {
467*71d10453SEric Joyner 	struct ice_label *label;
468*71d10453SEric Joyner 
469*71d10453SEric Joyner 	/* Check for valid label section on first call */
470*71d10453SEric Joyner 	if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST))
471*71d10453SEric Joyner 		return NULL;
472*71d10453SEric Joyner 
473*71d10453SEric Joyner 	label = (struct ice_label *)ice_pkg_enum_entry(ice_seg, state, type,
474*71d10453SEric Joyner 						       NULL,
475*71d10453SEric Joyner 						       ice_label_enum_handler);
476*71d10453SEric Joyner 	if (!label)
477*71d10453SEric Joyner 		return NULL;
478*71d10453SEric Joyner 
479*71d10453SEric Joyner 	*value = LE16_TO_CPU(label->value);
480*71d10453SEric Joyner 	return label->name;
481*71d10453SEric Joyner }
482*71d10453SEric Joyner 
483*71d10453SEric Joyner /**
484*71d10453SEric Joyner  * ice_init_pkg_hints
485*71d10453SEric Joyner  * @hw: pointer to the HW structure
486*71d10453SEric Joyner  * @ice_seg: pointer to the segment of the package scan (non-NULL)
487*71d10453SEric Joyner  *
488*71d10453SEric Joyner  * This function will scan the package and save off relevant information
489*71d10453SEric Joyner  * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
490*71d10453SEric Joyner  * since the first call to ice_enum_labels requires a pointer to an actual
491*71d10453SEric Joyner  * ice_seg structure.
492*71d10453SEric Joyner  */
493*71d10453SEric Joyner static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
494*71d10453SEric Joyner {
495*71d10453SEric Joyner 	struct ice_pkg_enum state;
496*71d10453SEric Joyner 	char *label_name;
497*71d10453SEric Joyner 	u16 val;
498*71d10453SEric Joyner 	int i;
499*71d10453SEric Joyner 
500*71d10453SEric Joyner 	ice_memset(&hw->tnl, 0, sizeof(hw->tnl), ICE_NONDMA_MEM);
501*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
502*71d10453SEric Joyner 
503*71d10453SEric Joyner 	if (!ice_seg)
504*71d10453SEric Joyner 		return;
505*71d10453SEric Joyner 
506*71d10453SEric Joyner 	label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
507*71d10453SEric Joyner 				     &val);
508*71d10453SEric Joyner 
509*71d10453SEric Joyner 	while (label_name && hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) {
510*71d10453SEric Joyner 		for (i = 0; tnls[i].type != TNL_LAST; i++) {
511*71d10453SEric Joyner 			size_t len = strlen(tnls[i].label_prefix);
512*71d10453SEric Joyner 
513*71d10453SEric Joyner 			/* Look for matching label start, before continuing */
514*71d10453SEric Joyner 			if (strncmp(label_name, tnls[i].label_prefix, len))
515*71d10453SEric Joyner 				continue;
516*71d10453SEric Joyner 
517*71d10453SEric Joyner 			/* Make sure this label matches our PF. Note that the PF
518*71d10453SEric Joyner 			 * character ('0' - '7') will be located where our
519*71d10453SEric Joyner 			 * prefix string's null terminator is located.
520*71d10453SEric Joyner 			 */
521*71d10453SEric Joyner 			if ((label_name[len] - '0') == hw->pf_id) {
522*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].type = tnls[i].type;
523*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].valid = false;
524*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].in_use = false;
525*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].marked = false;
526*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].boost_addr = val;
527*71d10453SEric Joyner 				hw->tnl.tbl[hw->tnl.count].port = 0;
528*71d10453SEric Joyner 				hw->tnl.count++;
529*71d10453SEric Joyner 				break;
530*71d10453SEric Joyner 			}
531*71d10453SEric Joyner 		}
532*71d10453SEric Joyner 
533*71d10453SEric Joyner 		label_name = ice_enum_labels(NULL, 0, &state, &val);
534*71d10453SEric Joyner 	}
535*71d10453SEric Joyner 
536*71d10453SEric Joyner 	/* Cache the appropriate boost TCAM entry pointers */
537*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count; i++) {
538*71d10453SEric Joyner 		ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
539*71d10453SEric Joyner 				     &hw->tnl.tbl[i].boost_entry);
540*71d10453SEric Joyner 		if (hw->tnl.tbl[i].boost_entry)
541*71d10453SEric Joyner 			hw->tnl.tbl[i].valid = true;
542*71d10453SEric Joyner 	}
543*71d10453SEric Joyner }
544*71d10453SEric Joyner 
545*71d10453SEric Joyner /* Key creation */
546*71d10453SEric Joyner 
547*71d10453SEric Joyner #define ICE_DC_KEY	0x1	/* don't care */
548*71d10453SEric Joyner #define ICE_DC_KEYINV	0x1
549*71d10453SEric Joyner #define ICE_NM_KEY	0x0	/* never match */
550*71d10453SEric Joyner #define ICE_NM_KEYINV	0x0
551*71d10453SEric Joyner #define ICE_0_KEY	0x1	/* match 0 */
552*71d10453SEric Joyner #define ICE_0_KEYINV	0x0
553*71d10453SEric Joyner #define ICE_1_KEY	0x0	/* match 1 */
554*71d10453SEric Joyner #define ICE_1_KEYINV	0x1
555*71d10453SEric Joyner 
556*71d10453SEric Joyner /**
557*71d10453SEric Joyner  * ice_gen_key_word - generate 16-bits of a key/mask word
558*71d10453SEric Joyner  * @val: the value
559*71d10453SEric Joyner  * @valid: valid bits mask (change only the valid bits)
560*71d10453SEric Joyner  * @dont_care: don't care mask
561*71d10453SEric Joyner  * @nvr_mtch: never match mask
562*71d10453SEric Joyner  * @key: pointer to an array of where the resulting key portion
563*71d10453SEric Joyner  * @key_inv: pointer to an array of where the resulting key invert portion
564*71d10453SEric Joyner  *
565*71d10453SEric Joyner  * This function generates 16-bits from a 8-bit value, an 8-bit don't care mask
566*71d10453SEric Joyner  * and an 8-bit never match mask. The 16-bits of output are divided into 8 bits
567*71d10453SEric Joyner  * of key and 8 bits of key invert.
568*71d10453SEric Joyner  *
569*71d10453SEric Joyner  *     '0' =    b01, always match a 0 bit
570*71d10453SEric Joyner  *     '1' =    b10, always match a 1 bit
571*71d10453SEric Joyner  *     '?' =    b11, don't care bit (always matches)
572*71d10453SEric Joyner  *     '~' =    b00, never match bit
573*71d10453SEric Joyner  *
574*71d10453SEric Joyner  * Input:
575*71d10453SEric Joyner  *          val:         b0  1  0  1  0  1
576*71d10453SEric Joyner  *          dont_care:   b0  0  1  1  0  0
577*71d10453SEric Joyner  *          never_mtch:  b0  0  0  0  1  1
578*71d10453SEric Joyner  *          ------------------------------
579*71d10453SEric Joyner  * Result:  key:        b01 10 11 11 00 00
580*71d10453SEric Joyner  */
581*71d10453SEric Joyner static enum ice_status
582*71d10453SEric Joyner ice_gen_key_word(u8 val, u8 valid, u8 dont_care, u8 nvr_mtch, u8 *key,
583*71d10453SEric Joyner 		 u8 *key_inv)
584*71d10453SEric Joyner {
585*71d10453SEric Joyner 	u8 in_key = *key, in_key_inv = *key_inv;
586*71d10453SEric Joyner 	u8 i;
587*71d10453SEric Joyner 
588*71d10453SEric Joyner 	/* 'dont_care' and 'nvr_mtch' masks cannot overlap */
589*71d10453SEric Joyner 	if ((dont_care ^ nvr_mtch) != (dont_care | nvr_mtch))
590*71d10453SEric Joyner 		return ICE_ERR_CFG;
591*71d10453SEric Joyner 
592*71d10453SEric Joyner 	*key = 0;
593*71d10453SEric Joyner 	*key_inv = 0;
594*71d10453SEric Joyner 
595*71d10453SEric Joyner 	/* encode the 8 bits into 8-bit key and 8-bit key invert */
596*71d10453SEric Joyner 	for (i = 0; i < 8; i++) {
597*71d10453SEric Joyner 		*key >>= 1;
598*71d10453SEric Joyner 		*key_inv >>= 1;
599*71d10453SEric Joyner 
600*71d10453SEric Joyner 		if (!(valid & 0x1)) { /* change only valid bits */
601*71d10453SEric Joyner 			*key |= (in_key & 0x1) << 7;
602*71d10453SEric Joyner 			*key_inv |= (in_key_inv & 0x1) << 7;
603*71d10453SEric Joyner 		} else if (dont_care & 0x1) { /* don't care bit */
604*71d10453SEric Joyner 			*key |= ICE_DC_KEY << 7;
605*71d10453SEric Joyner 			*key_inv |= ICE_DC_KEYINV << 7;
606*71d10453SEric Joyner 		} else if (nvr_mtch & 0x1) { /* never match bit */
607*71d10453SEric Joyner 			*key |= ICE_NM_KEY << 7;
608*71d10453SEric Joyner 			*key_inv |= ICE_NM_KEYINV << 7;
609*71d10453SEric Joyner 		} else if (val & 0x01) { /* exact 1 match */
610*71d10453SEric Joyner 			*key |= ICE_1_KEY << 7;
611*71d10453SEric Joyner 			*key_inv |= ICE_1_KEYINV << 7;
612*71d10453SEric Joyner 		} else { /* exact 0 match */
613*71d10453SEric Joyner 			*key |= ICE_0_KEY << 7;
614*71d10453SEric Joyner 			*key_inv |= ICE_0_KEYINV << 7;
615*71d10453SEric Joyner 		}
616*71d10453SEric Joyner 
617*71d10453SEric Joyner 		dont_care >>= 1;
618*71d10453SEric Joyner 		nvr_mtch >>= 1;
619*71d10453SEric Joyner 		valid >>= 1;
620*71d10453SEric Joyner 		val >>= 1;
621*71d10453SEric Joyner 		in_key >>= 1;
622*71d10453SEric Joyner 		in_key_inv >>= 1;
623*71d10453SEric Joyner 	}
624*71d10453SEric Joyner 
625*71d10453SEric Joyner 	return ICE_SUCCESS;
626*71d10453SEric Joyner }
627*71d10453SEric Joyner 
628*71d10453SEric Joyner /**
629*71d10453SEric Joyner  * ice_bits_max_set - determine if the number of bits set is within a maximum
630*71d10453SEric Joyner  * @mask: pointer to the byte array which is the mask
631*71d10453SEric Joyner  * @size: the number of bytes in the mask
632*71d10453SEric Joyner  * @max: the max number of set bits
633*71d10453SEric Joyner  *
634*71d10453SEric Joyner  * This function determines if there are at most 'max' number of bits set in an
635*71d10453SEric Joyner  * array. Returns true if the number for bits set is <= max or will return false
636*71d10453SEric Joyner  * otherwise.
637*71d10453SEric Joyner  */
638*71d10453SEric Joyner static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max)
639*71d10453SEric Joyner {
640*71d10453SEric Joyner 	u16 count = 0;
641*71d10453SEric Joyner 	u16 i;
642*71d10453SEric Joyner 
643*71d10453SEric Joyner 	/* check each byte */
644*71d10453SEric Joyner 	for (i = 0; i < size; i++) {
645*71d10453SEric Joyner 		/* if 0, go to next byte */
646*71d10453SEric Joyner 		if (!mask[i])
647*71d10453SEric Joyner 			continue;
648*71d10453SEric Joyner 
649*71d10453SEric Joyner 		/* We know there is at least one set bit in this byte because of
650*71d10453SEric Joyner 		 * the above check; if we already have found 'max' number of
651*71d10453SEric Joyner 		 * bits set, then we can return failure now.
652*71d10453SEric Joyner 		 */
653*71d10453SEric Joyner 		if (count == max)
654*71d10453SEric Joyner 			return false;
655*71d10453SEric Joyner 
656*71d10453SEric Joyner 		/* count the bits in this byte, checking threshold */
657*71d10453SEric Joyner 		count += ice_hweight8(mask[i]);
658*71d10453SEric Joyner 		if (count > max)
659*71d10453SEric Joyner 			return false;
660*71d10453SEric Joyner 	}
661*71d10453SEric Joyner 
662*71d10453SEric Joyner 	return true;
663*71d10453SEric Joyner }
664*71d10453SEric Joyner 
665*71d10453SEric Joyner /**
666*71d10453SEric Joyner  * ice_set_key - generate a variable sized key with multiples of 16-bits
667*71d10453SEric Joyner  * @key: pointer to where the key will be stored
668*71d10453SEric Joyner  * @size: the size of the complete key in bytes (must be even)
669*71d10453SEric Joyner  * @val: array of 8-bit values that makes up the value portion of the key
670*71d10453SEric Joyner  * @upd: array of 8-bit masks that determine what key portion to update
671*71d10453SEric Joyner  * @dc: array of 8-bit masks that make up the don't care mask
672*71d10453SEric Joyner  * @nm: array of 8-bit masks that make up the never match mask
673*71d10453SEric Joyner  * @off: the offset of the first byte in the key to update
674*71d10453SEric Joyner  * @len: the number of bytes in the key update
675*71d10453SEric Joyner  *
676*71d10453SEric Joyner  * This function generates a key from a value, a don't care mask and a never
677*71d10453SEric Joyner  * match mask.
678*71d10453SEric Joyner  * upd, dc, and nm are optional parameters, and can be NULL:
679*71d10453SEric Joyner  *	upd == NULL --> udp mask is all 1's (update all bits)
680*71d10453SEric Joyner  *	dc == NULL --> dc mask is all 0's (no don't care bits)
681*71d10453SEric Joyner  *	nm == NULL --> nm mask is all 0's (no never match bits)
682*71d10453SEric Joyner  */
683*71d10453SEric Joyner enum ice_status
684*71d10453SEric Joyner ice_set_key(u8 *key, u16 size, u8 *val, u8 *upd, u8 *dc, u8 *nm, u16 off,
685*71d10453SEric Joyner 	    u16 len)
686*71d10453SEric Joyner {
687*71d10453SEric Joyner 	u16 half_size;
688*71d10453SEric Joyner 	u16 i;
689*71d10453SEric Joyner 
690*71d10453SEric Joyner 	/* size must be a multiple of 2 bytes. */
691*71d10453SEric Joyner 	if (size % 2)
692*71d10453SEric Joyner 		return ICE_ERR_CFG;
693*71d10453SEric Joyner 	half_size = size / 2;
694*71d10453SEric Joyner 
695*71d10453SEric Joyner 	if (off + len > half_size)
696*71d10453SEric Joyner 		return ICE_ERR_CFG;
697*71d10453SEric Joyner 
698*71d10453SEric Joyner 	/* Make sure at most one bit is set in the never match mask. Having more
699*71d10453SEric Joyner 	 * than one never match mask bit set will cause HW to consume excessive
700*71d10453SEric Joyner 	 * power otherwise; this is a power management efficiency check.
701*71d10453SEric Joyner 	 */
702*71d10453SEric Joyner #define ICE_NVR_MTCH_BITS_MAX	1
703*71d10453SEric Joyner 	if (nm && !ice_bits_max_set(nm, len, ICE_NVR_MTCH_BITS_MAX))
704*71d10453SEric Joyner 		return ICE_ERR_CFG;
705*71d10453SEric Joyner 
706*71d10453SEric Joyner 	for (i = 0; i < len; i++)
707*71d10453SEric Joyner 		if (ice_gen_key_word(val[i], upd ? upd[i] : 0xff,
708*71d10453SEric Joyner 				     dc ? dc[i] : 0, nm ? nm[i] : 0,
709*71d10453SEric Joyner 				     key + off + i, key + half_size + off + i))
710*71d10453SEric Joyner 			return ICE_ERR_CFG;
711*71d10453SEric Joyner 
712*71d10453SEric Joyner 	return ICE_SUCCESS;
713*71d10453SEric Joyner }
714*71d10453SEric Joyner 
715*71d10453SEric Joyner /**
716*71d10453SEric Joyner  * ice_acquire_global_cfg_lock
717*71d10453SEric Joyner  * @hw: pointer to the HW structure
718*71d10453SEric Joyner  * @access: access type (read or write)
719*71d10453SEric Joyner  *
720*71d10453SEric Joyner  * This function will request ownership of the global config lock for reading
721*71d10453SEric Joyner  * or writing of the package. When attempting to obtain write access, the
722*71d10453SEric Joyner  * caller must check for the following two return values:
723*71d10453SEric Joyner  *
724*71d10453SEric Joyner  * ICE_SUCCESS        - Means the caller has acquired the global config lock
725*71d10453SEric Joyner  *                      and can perform writing of the package.
726*71d10453SEric Joyner  * ICE_ERR_AQ_NO_WORK - Indicates another driver has already written the
727*71d10453SEric Joyner  *                      package or has found that no update was necessary; in
728*71d10453SEric Joyner  *                      this case, the caller can just skip performing any
729*71d10453SEric Joyner  *                      update of the package.
730*71d10453SEric Joyner  */
731*71d10453SEric Joyner static enum ice_status
732*71d10453SEric Joyner ice_acquire_global_cfg_lock(struct ice_hw *hw,
733*71d10453SEric Joyner 			    enum ice_aq_res_access_type access)
734*71d10453SEric Joyner {
735*71d10453SEric Joyner 	enum ice_status status;
736*71d10453SEric Joyner 
737*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
738*71d10453SEric Joyner 
739*71d10453SEric Joyner 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
740*71d10453SEric Joyner 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
741*71d10453SEric Joyner 
742*71d10453SEric Joyner 	if (status == ICE_ERR_AQ_NO_WORK)
743*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG,
744*71d10453SEric Joyner 			  "Global config lock: No work to do\n");
745*71d10453SEric Joyner 
746*71d10453SEric Joyner 	return status;
747*71d10453SEric Joyner }
748*71d10453SEric Joyner 
749*71d10453SEric Joyner /**
750*71d10453SEric Joyner  * ice_release_global_cfg_lock
751*71d10453SEric Joyner  * @hw: pointer to the HW structure
752*71d10453SEric Joyner  *
753*71d10453SEric Joyner  * This function will release the global config lock.
754*71d10453SEric Joyner  */
755*71d10453SEric Joyner static void ice_release_global_cfg_lock(struct ice_hw *hw)
756*71d10453SEric Joyner {
757*71d10453SEric Joyner 	ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID);
758*71d10453SEric Joyner }
759*71d10453SEric Joyner 
760*71d10453SEric Joyner /**
761*71d10453SEric Joyner  * ice_acquire_change_lock
762*71d10453SEric Joyner  * @hw: pointer to the HW structure
763*71d10453SEric Joyner  * @access: access type (read or write)
764*71d10453SEric Joyner  *
765*71d10453SEric Joyner  * This function will request ownership of the change lock.
766*71d10453SEric Joyner  */
767*71d10453SEric Joyner enum ice_status
768*71d10453SEric Joyner ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
769*71d10453SEric Joyner {
770*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
771*71d10453SEric Joyner 
772*71d10453SEric Joyner 	return ice_acquire_res(hw, ICE_CHANGE_LOCK_RES_ID, access,
773*71d10453SEric Joyner 			       ICE_CHANGE_LOCK_TIMEOUT);
774*71d10453SEric Joyner }
775*71d10453SEric Joyner 
776*71d10453SEric Joyner /**
777*71d10453SEric Joyner  * ice_release_change_lock
778*71d10453SEric Joyner  * @hw: pointer to the HW structure
779*71d10453SEric Joyner  *
780*71d10453SEric Joyner  * This function will release the change lock using the proper Admin Command.
781*71d10453SEric Joyner  */
782*71d10453SEric Joyner void ice_release_change_lock(struct ice_hw *hw)
783*71d10453SEric Joyner {
784*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
785*71d10453SEric Joyner 
786*71d10453SEric Joyner 	ice_release_res(hw, ICE_CHANGE_LOCK_RES_ID);
787*71d10453SEric Joyner }
788*71d10453SEric Joyner 
789*71d10453SEric Joyner /**
790*71d10453SEric Joyner  * ice_aq_download_pkg
791*71d10453SEric Joyner  * @hw: pointer to the hardware structure
792*71d10453SEric Joyner  * @pkg_buf: the package buffer to transfer
793*71d10453SEric Joyner  * @buf_size: the size of the package buffer
794*71d10453SEric Joyner  * @last_buf: last buffer indicator
795*71d10453SEric Joyner  * @error_offset: returns error offset
796*71d10453SEric Joyner  * @error_info: returns error information
797*71d10453SEric Joyner  * @cd: pointer to command details structure or NULL
798*71d10453SEric Joyner  *
799*71d10453SEric Joyner  * Download Package (0x0C40)
800*71d10453SEric Joyner  */
801*71d10453SEric Joyner static enum ice_status
802*71d10453SEric Joyner ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
803*71d10453SEric Joyner 		    u16 buf_size, bool last_buf, u32 *error_offset,
804*71d10453SEric Joyner 		    u32 *error_info, struct ice_sq_cd *cd)
805*71d10453SEric Joyner {
806*71d10453SEric Joyner 	struct ice_aqc_download_pkg *cmd;
807*71d10453SEric Joyner 	struct ice_aq_desc desc;
808*71d10453SEric Joyner 	enum ice_status status;
809*71d10453SEric Joyner 
810*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
811*71d10453SEric Joyner 
812*71d10453SEric Joyner 	if (error_offset)
813*71d10453SEric Joyner 		*error_offset = 0;
814*71d10453SEric Joyner 	if (error_info)
815*71d10453SEric Joyner 		*error_info = 0;
816*71d10453SEric Joyner 
817*71d10453SEric Joyner 	cmd = &desc.params.download_pkg;
818*71d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
819*71d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
820*71d10453SEric Joyner 
821*71d10453SEric Joyner 	if (last_buf)
822*71d10453SEric Joyner 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
823*71d10453SEric Joyner 
824*71d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
825*71d10453SEric Joyner 	if (status == ICE_ERR_AQ_ERROR) {
826*71d10453SEric Joyner 		/* Read error from buffer only when the FW returned an error */
827*71d10453SEric Joyner 		struct ice_aqc_download_pkg_resp *resp;
828*71d10453SEric Joyner 
829*71d10453SEric Joyner 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
830*71d10453SEric Joyner 		if (error_offset)
831*71d10453SEric Joyner 			*error_offset = LE32_TO_CPU(resp->error_offset);
832*71d10453SEric Joyner 		if (error_info)
833*71d10453SEric Joyner 			*error_info = LE32_TO_CPU(resp->error_info);
834*71d10453SEric Joyner 	}
835*71d10453SEric Joyner 
836*71d10453SEric Joyner 	return status;
837*71d10453SEric Joyner }
838*71d10453SEric Joyner 
839*71d10453SEric Joyner /**
840*71d10453SEric Joyner  * ice_aq_upload_section
841*71d10453SEric Joyner  * @hw: pointer to the hardware structure
842*71d10453SEric Joyner  * @pkg_buf: the package buffer which will receive the section
843*71d10453SEric Joyner  * @buf_size: the size of the package buffer
844*71d10453SEric Joyner  * @cd: pointer to command details structure or NULL
845*71d10453SEric Joyner  *
846*71d10453SEric Joyner  * Upload Section (0x0C41)
847*71d10453SEric Joyner  */
848*71d10453SEric Joyner enum ice_status
849*71d10453SEric Joyner ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
850*71d10453SEric Joyner 		      u16 buf_size, struct ice_sq_cd *cd)
851*71d10453SEric Joyner {
852*71d10453SEric Joyner 	struct ice_aq_desc desc;
853*71d10453SEric Joyner 
854*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
855*71d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
856*71d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
857*71d10453SEric Joyner 
858*71d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
859*71d10453SEric Joyner }
860*71d10453SEric Joyner 
861*71d10453SEric Joyner /**
862*71d10453SEric Joyner  * ice_aq_update_pkg
863*71d10453SEric Joyner  * @hw: pointer to the hardware structure
864*71d10453SEric Joyner  * @pkg_buf: the package cmd buffer
865*71d10453SEric Joyner  * @buf_size: the size of the package cmd buffer
866*71d10453SEric Joyner  * @last_buf: last buffer indicator
867*71d10453SEric Joyner  * @error_offset: returns error offset
868*71d10453SEric Joyner  * @error_info: returns error information
869*71d10453SEric Joyner  * @cd: pointer to command details structure or NULL
870*71d10453SEric Joyner  *
871*71d10453SEric Joyner  * Update Package (0x0C42)
872*71d10453SEric Joyner  */
873*71d10453SEric Joyner static enum ice_status
874*71d10453SEric Joyner ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size,
875*71d10453SEric Joyner 		  bool last_buf, u32 *error_offset, u32 *error_info,
876*71d10453SEric Joyner 		  struct ice_sq_cd *cd)
877*71d10453SEric Joyner {
878*71d10453SEric Joyner 	struct ice_aqc_download_pkg *cmd;
879*71d10453SEric Joyner 	struct ice_aq_desc desc;
880*71d10453SEric Joyner 	enum ice_status status;
881*71d10453SEric Joyner 
882*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
883*71d10453SEric Joyner 
884*71d10453SEric Joyner 	if (error_offset)
885*71d10453SEric Joyner 		*error_offset = 0;
886*71d10453SEric Joyner 	if (error_info)
887*71d10453SEric Joyner 		*error_info = 0;
888*71d10453SEric Joyner 
889*71d10453SEric Joyner 	cmd = &desc.params.download_pkg;
890*71d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
891*71d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
892*71d10453SEric Joyner 
893*71d10453SEric Joyner 	if (last_buf)
894*71d10453SEric Joyner 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
895*71d10453SEric Joyner 
896*71d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
897*71d10453SEric Joyner 	if (status == ICE_ERR_AQ_ERROR) {
898*71d10453SEric Joyner 		/* Read error from buffer only when the FW returned an error */
899*71d10453SEric Joyner 		struct ice_aqc_download_pkg_resp *resp;
900*71d10453SEric Joyner 
901*71d10453SEric Joyner 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
902*71d10453SEric Joyner 		if (error_offset)
903*71d10453SEric Joyner 			*error_offset = LE32_TO_CPU(resp->error_offset);
904*71d10453SEric Joyner 		if (error_info)
905*71d10453SEric Joyner 			*error_info = LE32_TO_CPU(resp->error_info);
906*71d10453SEric Joyner 	}
907*71d10453SEric Joyner 
908*71d10453SEric Joyner 	return status;
909*71d10453SEric Joyner }
910*71d10453SEric Joyner 
911*71d10453SEric Joyner /**
912*71d10453SEric Joyner  * ice_find_seg_in_pkg
913*71d10453SEric Joyner  * @hw: pointer to the hardware structure
914*71d10453SEric Joyner  * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
915*71d10453SEric Joyner  * @pkg_hdr: pointer to the package header to be searched
916*71d10453SEric Joyner  *
917*71d10453SEric Joyner  * This function searches a package file for a particular segment type. On
918*71d10453SEric Joyner  * success it returns a pointer to the segment header, otherwise it will
919*71d10453SEric Joyner  * return NULL.
920*71d10453SEric Joyner  */
921*71d10453SEric Joyner static struct ice_generic_seg_hdr *
922*71d10453SEric Joyner ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
923*71d10453SEric Joyner 		    struct ice_pkg_hdr *pkg_hdr)
924*71d10453SEric Joyner {
925*71d10453SEric Joyner 	u32 i;
926*71d10453SEric Joyner 
927*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
928*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
929*71d10453SEric Joyner 		  pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
930*71d10453SEric Joyner 		  pkg_hdr->pkg_format_ver.update,
931*71d10453SEric Joyner 		  pkg_hdr->pkg_format_ver.draft);
932*71d10453SEric Joyner 
933*71d10453SEric Joyner 	/* Search all package segments for the requested segment type */
934*71d10453SEric Joyner 	for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
935*71d10453SEric Joyner 		struct ice_generic_seg_hdr *seg;
936*71d10453SEric Joyner 
937*71d10453SEric Joyner 		seg = (struct ice_generic_seg_hdr *)
938*71d10453SEric Joyner 			((u8 *)pkg_hdr + LE32_TO_CPU(pkg_hdr->seg_offset[i]));
939*71d10453SEric Joyner 
940*71d10453SEric Joyner 		if (LE32_TO_CPU(seg->seg_type) == seg_type)
941*71d10453SEric Joyner 			return seg;
942*71d10453SEric Joyner 	}
943*71d10453SEric Joyner 
944*71d10453SEric Joyner 	return NULL;
945*71d10453SEric Joyner }
946*71d10453SEric Joyner 
947*71d10453SEric Joyner /**
948*71d10453SEric Joyner  * ice_update_pkg
949*71d10453SEric Joyner  * @hw: pointer to the hardware structure
950*71d10453SEric Joyner  * @bufs: pointer to an array of buffers
951*71d10453SEric Joyner  * @count: the number of buffers in the array
952*71d10453SEric Joyner  *
953*71d10453SEric Joyner  * Obtains change lock and updates package.
954*71d10453SEric Joyner  */
955*71d10453SEric Joyner enum ice_status
956*71d10453SEric Joyner ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
957*71d10453SEric Joyner {
958*71d10453SEric Joyner 	enum ice_status status;
959*71d10453SEric Joyner 	u32 offset, info, i;
960*71d10453SEric Joyner 
961*71d10453SEric Joyner 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
962*71d10453SEric Joyner 	if (status)
963*71d10453SEric Joyner 		return status;
964*71d10453SEric Joyner 
965*71d10453SEric Joyner 	for (i = 0; i < count; i++) {
966*71d10453SEric Joyner 		struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
967*71d10453SEric Joyner 		bool last = ((i + 1) == count);
968*71d10453SEric Joyner 
969*71d10453SEric Joyner 		status = ice_aq_update_pkg(hw, bh, LE16_TO_CPU(bh->data_end),
970*71d10453SEric Joyner 					   last, &offset, &info, NULL);
971*71d10453SEric Joyner 
972*71d10453SEric Joyner 		if (status) {
973*71d10453SEric Joyner 			ice_debug(hw, ICE_DBG_PKG,
974*71d10453SEric Joyner 				  "Update pkg failed: err %d off %d inf %d\n",
975*71d10453SEric Joyner 				  status, offset, info);
976*71d10453SEric Joyner 			break;
977*71d10453SEric Joyner 		}
978*71d10453SEric Joyner 	}
979*71d10453SEric Joyner 
980*71d10453SEric Joyner 	ice_release_change_lock(hw);
981*71d10453SEric Joyner 
982*71d10453SEric Joyner 	return status;
983*71d10453SEric Joyner }
984*71d10453SEric Joyner 
985*71d10453SEric Joyner /**
986*71d10453SEric Joyner  * ice_dwnld_cfg_bufs
987*71d10453SEric Joyner  * @hw: pointer to the hardware structure
988*71d10453SEric Joyner  * @bufs: pointer to an array of buffers
989*71d10453SEric Joyner  * @count: the number of buffers in the array
990*71d10453SEric Joyner  *
991*71d10453SEric Joyner  * Obtains global config lock and downloads the package configuration buffers
992*71d10453SEric Joyner  * to the firmware. Metadata buffers are skipped, and the first metadata buffer
993*71d10453SEric Joyner  * found indicates that the rest of the buffers are all metadata buffers.
994*71d10453SEric Joyner  */
995*71d10453SEric Joyner static enum ice_status
996*71d10453SEric Joyner ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
997*71d10453SEric Joyner {
998*71d10453SEric Joyner 	enum ice_status status;
999*71d10453SEric Joyner 	struct ice_buf_hdr *bh;
1000*71d10453SEric Joyner 	u32 offset, info, i;
1001*71d10453SEric Joyner 
1002*71d10453SEric Joyner 	if (!bufs || !count)
1003*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1004*71d10453SEric Joyner 
1005*71d10453SEric Joyner 	/* If the first buffer's first section has its metadata bit set
1006*71d10453SEric Joyner 	 * then there are no buffers to be downloaded, and the operation is
1007*71d10453SEric Joyner 	 * considered a success.
1008*71d10453SEric Joyner 	 */
1009*71d10453SEric Joyner 	bh = (struct ice_buf_hdr *)bufs;
1010*71d10453SEric Joyner 	if (LE32_TO_CPU(bh->section_entry[0].type) & ICE_METADATA_BUF)
1011*71d10453SEric Joyner 		return ICE_SUCCESS;
1012*71d10453SEric Joyner 
1013*71d10453SEric Joyner 	/* reset pkg_dwnld_status in case this function is called in the
1014*71d10453SEric Joyner 	 * reset/rebuild flow
1015*71d10453SEric Joyner 	 */
1016*71d10453SEric Joyner 	hw->pkg_dwnld_status = ICE_AQ_RC_OK;
1017*71d10453SEric Joyner 
1018*71d10453SEric Joyner 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
1019*71d10453SEric Joyner 	if (status) {
1020*71d10453SEric Joyner 		if (status == ICE_ERR_AQ_NO_WORK)
1021*71d10453SEric Joyner 			hw->pkg_dwnld_status = ICE_AQ_RC_EEXIST;
1022*71d10453SEric Joyner 		else
1023*71d10453SEric Joyner 			hw->pkg_dwnld_status = hw->adminq.sq_last_status;
1024*71d10453SEric Joyner 		return status;
1025*71d10453SEric Joyner 	}
1026*71d10453SEric Joyner 
1027*71d10453SEric Joyner 	for (i = 0; i < count; i++) {
1028*71d10453SEric Joyner 		bool last = ((i + 1) == count);
1029*71d10453SEric Joyner 
1030*71d10453SEric Joyner 		if (!last) {
1031*71d10453SEric Joyner 			/* check next buffer for metadata flag */
1032*71d10453SEric Joyner 			bh = (struct ice_buf_hdr *)(bufs + i + 1);
1033*71d10453SEric Joyner 
1034*71d10453SEric Joyner 			/* A set metadata flag in the next buffer will signal
1035*71d10453SEric Joyner 			 * that the current buffer will be the last buffer
1036*71d10453SEric Joyner 			 * downloaded
1037*71d10453SEric Joyner 			 */
1038*71d10453SEric Joyner 			if (LE16_TO_CPU(bh->section_count))
1039*71d10453SEric Joyner 				if (LE32_TO_CPU(bh->section_entry[0].type) &
1040*71d10453SEric Joyner 				    ICE_METADATA_BUF)
1041*71d10453SEric Joyner 					last = true;
1042*71d10453SEric Joyner 		}
1043*71d10453SEric Joyner 
1044*71d10453SEric Joyner 		bh = (struct ice_buf_hdr *)(bufs + i);
1045*71d10453SEric Joyner 
1046*71d10453SEric Joyner 		status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
1047*71d10453SEric Joyner 					     &offset, &info, NULL);
1048*71d10453SEric Joyner 
1049*71d10453SEric Joyner 		/* Save AQ status from download package */
1050*71d10453SEric Joyner 		hw->pkg_dwnld_status = hw->adminq.sq_last_status;
1051*71d10453SEric Joyner 		if (status) {
1052*71d10453SEric Joyner 			ice_debug(hw, ICE_DBG_PKG,
1053*71d10453SEric Joyner 				  "Pkg download failed: err %d off %d inf %d\n",
1054*71d10453SEric Joyner 				  status, offset, info);
1055*71d10453SEric Joyner 
1056*71d10453SEric Joyner 			break;
1057*71d10453SEric Joyner 		}
1058*71d10453SEric Joyner 
1059*71d10453SEric Joyner 		if (last)
1060*71d10453SEric Joyner 			break;
1061*71d10453SEric Joyner 	}
1062*71d10453SEric Joyner 
1063*71d10453SEric Joyner 	ice_release_global_cfg_lock(hw);
1064*71d10453SEric Joyner 
1065*71d10453SEric Joyner 	return status;
1066*71d10453SEric Joyner }
1067*71d10453SEric Joyner 
1068*71d10453SEric Joyner /**
1069*71d10453SEric Joyner  * ice_aq_get_pkg_info_list
1070*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1071*71d10453SEric Joyner  * @pkg_info: the buffer which will receive the information list
1072*71d10453SEric Joyner  * @buf_size: the size of the pkg_info information buffer
1073*71d10453SEric Joyner  * @cd: pointer to command details structure or NULL
1074*71d10453SEric Joyner  *
1075*71d10453SEric Joyner  * Get Package Info List (0x0C43)
1076*71d10453SEric Joyner  */
1077*71d10453SEric Joyner static enum ice_status
1078*71d10453SEric Joyner ice_aq_get_pkg_info_list(struct ice_hw *hw,
1079*71d10453SEric Joyner 			 struct ice_aqc_get_pkg_info_resp *pkg_info,
1080*71d10453SEric Joyner 			 u16 buf_size, struct ice_sq_cd *cd)
1081*71d10453SEric Joyner {
1082*71d10453SEric Joyner 	struct ice_aq_desc desc;
1083*71d10453SEric Joyner 
1084*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
1085*71d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
1086*71d10453SEric Joyner 
1087*71d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
1088*71d10453SEric Joyner }
1089*71d10453SEric Joyner 
1090*71d10453SEric Joyner /**
1091*71d10453SEric Joyner  * ice_download_pkg
1092*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1093*71d10453SEric Joyner  * @ice_seg: pointer to the segment of the package to be downloaded
1094*71d10453SEric Joyner  *
1095*71d10453SEric Joyner  * Handles the download of a complete package.
1096*71d10453SEric Joyner  */
1097*71d10453SEric Joyner static enum ice_status
1098*71d10453SEric Joyner ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg)
1099*71d10453SEric Joyner {
1100*71d10453SEric Joyner 	struct ice_buf_table *ice_buf_tbl;
1101*71d10453SEric Joyner 
1102*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
1103*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
1104*71d10453SEric Joyner 		  ice_seg->hdr.seg_format_ver.major,
1105*71d10453SEric Joyner 		  ice_seg->hdr.seg_format_ver.minor,
1106*71d10453SEric Joyner 		  ice_seg->hdr.seg_format_ver.update,
1107*71d10453SEric Joyner 		  ice_seg->hdr.seg_format_ver.draft);
1108*71d10453SEric Joyner 
1109*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
1110*71d10453SEric Joyner 		  LE32_TO_CPU(ice_seg->hdr.seg_type),
1111*71d10453SEric Joyner 		  LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
1112*71d10453SEric Joyner 
1113*71d10453SEric Joyner 	ice_buf_tbl = ice_find_buf_table(ice_seg);
1114*71d10453SEric Joyner 
1115*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
1116*71d10453SEric Joyner 		  LE32_TO_CPU(ice_buf_tbl->buf_count));
1117*71d10453SEric Joyner 
1118*71d10453SEric Joyner 	return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
1119*71d10453SEric Joyner 				  LE32_TO_CPU(ice_buf_tbl->buf_count));
1120*71d10453SEric Joyner }
1121*71d10453SEric Joyner 
1122*71d10453SEric Joyner /**
1123*71d10453SEric Joyner  * ice_init_pkg_info
1124*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1125*71d10453SEric Joyner  * @pkg_hdr: pointer to the driver's package hdr
1126*71d10453SEric Joyner  *
1127*71d10453SEric Joyner  * Saves off the package details into the HW structure.
1128*71d10453SEric Joyner  */
1129*71d10453SEric Joyner static enum ice_status
1130*71d10453SEric Joyner ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
1131*71d10453SEric Joyner {
1132*71d10453SEric Joyner 	struct ice_global_metadata_seg *meta_seg;
1133*71d10453SEric Joyner 	struct ice_generic_seg_hdr *seg_hdr;
1134*71d10453SEric Joyner 
1135*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
1136*71d10453SEric Joyner 	if (!pkg_hdr)
1137*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1138*71d10453SEric Joyner 
1139*71d10453SEric Joyner 	meta_seg = (struct ice_global_metadata_seg *)
1140*71d10453SEric Joyner 		   ice_find_seg_in_pkg(hw, SEGMENT_TYPE_METADATA, pkg_hdr);
1141*71d10453SEric Joyner 	if (meta_seg) {
1142*71d10453SEric Joyner 		hw->pkg_ver = meta_seg->pkg_ver;
1143*71d10453SEric Joyner 		ice_memcpy(hw->pkg_name, meta_seg->pkg_name,
1144*71d10453SEric Joyner 			   sizeof(hw->pkg_name), ICE_NONDMA_TO_NONDMA);
1145*71d10453SEric Joyner 
1146*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
1147*71d10453SEric Joyner 			  meta_seg->pkg_ver.major, meta_seg->pkg_ver.minor,
1148*71d10453SEric Joyner 			  meta_seg->pkg_ver.update, meta_seg->pkg_ver.draft,
1149*71d10453SEric Joyner 			  meta_seg->pkg_name);
1150*71d10453SEric Joyner 	} else {
1151*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT,
1152*71d10453SEric Joyner 			  "Did not find metadata segment in driver package\n");
1153*71d10453SEric Joyner 		return ICE_ERR_CFG;
1154*71d10453SEric Joyner 	}
1155*71d10453SEric Joyner 
1156*71d10453SEric Joyner 	seg_hdr = ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg_hdr);
1157*71d10453SEric Joyner 	if (seg_hdr) {
1158*71d10453SEric Joyner 		hw->ice_pkg_ver = seg_hdr->seg_format_ver;
1159*71d10453SEric Joyner 		ice_memcpy(hw->ice_pkg_name, seg_hdr->seg_id,
1160*71d10453SEric Joyner 			   sizeof(hw->ice_pkg_name), ICE_NONDMA_TO_NONDMA);
1161*71d10453SEric Joyner 
1162*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
1163*71d10453SEric Joyner 			  seg_hdr->seg_format_ver.major,
1164*71d10453SEric Joyner 			  seg_hdr->seg_format_ver.minor,
1165*71d10453SEric Joyner 			  seg_hdr->seg_format_ver.update,
1166*71d10453SEric Joyner 			  seg_hdr->seg_format_ver.draft,
1167*71d10453SEric Joyner 			  seg_hdr->seg_id);
1168*71d10453SEric Joyner 	} else {
1169*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT,
1170*71d10453SEric Joyner 			  "Did not find ice segment in driver package\n");
1171*71d10453SEric Joyner 		return ICE_ERR_CFG;
1172*71d10453SEric Joyner 	}
1173*71d10453SEric Joyner 
1174*71d10453SEric Joyner 	return ICE_SUCCESS;
1175*71d10453SEric Joyner }
1176*71d10453SEric Joyner 
1177*71d10453SEric Joyner /**
1178*71d10453SEric Joyner  * ice_get_pkg_info
1179*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1180*71d10453SEric Joyner  *
1181*71d10453SEric Joyner  * Store details of the package currently loaded in HW into the HW structure.
1182*71d10453SEric Joyner  */
1183*71d10453SEric Joyner static enum ice_status ice_get_pkg_info(struct ice_hw *hw)
1184*71d10453SEric Joyner {
1185*71d10453SEric Joyner 	struct ice_aqc_get_pkg_info_resp *pkg_info;
1186*71d10453SEric Joyner 	enum ice_status status;
1187*71d10453SEric Joyner 	u16 size;
1188*71d10453SEric Joyner 	u32 i;
1189*71d10453SEric Joyner 
1190*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
1191*71d10453SEric Joyner 
1192*71d10453SEric Joyner 	size = ice_struct_size(pkg_info, pkg_info, ICE_PKG_CNT - 1);
1193*71d10453SEric Joyner 	pkg_info = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
1194*71d10453SEric Joyner 	if (!pkg_info)
1195*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
1196*71d10453SEric Joyner 
1197*71d10453SEric Joyner 	status = ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL);
1198*71d10453SEric Joyner 	if (status)
1199*71d10453SEric Joyner 		goto init_pkg_free_alloc;
1200*71d10453SEric Joyner 
1201*71d10453SEric Joyner 	for (i = 0; i < LE32_TO_CPU(pkg_info->count); i++) {
1202*71d10453SEric Joyner #define ICE_PKG_FLAG_COUNT	4
1203*71d10453SEric Joyner 		char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
1204*71d10453SEric Joyner 		u8 place = 0;
1205*71d10453SEric Joyner 
1206*71d10453SEric Joyner 		if (pkg_info->pkg_info[i].is_active) {
1207*71d10453SEric Joyner 			flags[place++] = 'A';
1208*71d10453SEric Joyner 			hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
1209*71d10453SEric Joyner 			hw->active_track_id =
1210*71d10453SEric Joyner 				LE32_TO_CPU(pkg_info->pkg_info[i].track_id);
1211*71d10453SEric Joyner 			ice_memcpy(hw->active_pkg_name,
1212*71d10453SEric Joyner 				   pkg_info->pkg_info[i].name,
1213*71d10453SEric Joyner 				   sizeof(pkg_info->pkg_info[i].name),
1214*71d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
1215*71d10453SEric Joyner 			hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
1216*71d10453SEric Joyner 		}
1217*71d10453SEric Joyner 		if (pkg_info->pkg_info[i].is_active_at_boot)
1218*71d10453SEric Joyner 			flags[place++] = 'B';
1219*71d10453SEric Joyner 		if (pkg_info->pkg_info[i].is_modified)
1220*71d10453SEric Joyner 			flags[place++] = 'M';
1221*71d10453SEric Joyner 		if (pkg_info->pkg_info[i].is_in_nvm)
1222*71d10453SEric Joyner 			flags[place++] = 'N';
1223*71d10453SEric Joyner 
1224*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n",
1225*71d10453SEric Joyner 			  i, pkg_info->pkg_info[i].ver.major,
1226*71d10453SEric Joyner 			  pkg_info->pkg_info[i].ver.minor,
1227*71d10453SEric Joyner 			  pkg_info->pkg_info[i].ver.update,
1228*71d10453SEric Joyner 			  pkg_info->pkg_info[i].ver.draft,
1229*71d10453SEric Joyner 			  pkg_info->pkg_info[i].name, flags);
1230*71d10453SEric Joyner 	}
1231*71d10453SEric Joyner 
1232*71d10453SEric Joyner init_pkg_free_alloc:
1233*71d10453SEric Joyner 	ice_free(hw, pkg_info);
1234*71d10453SEric Joyner 
1235*71d10453SEric Joyner 	return status;
1236*71d10453SEric Joyner }
1237*71d10453SEric Joyner 
1238*71d10453SEric Joyner /**
1239*71d10453SEric Joyner  * ice_find_label_value
1240*71d10453SEric Joyner  * @ice_seg: pointer to the ice segment (non-NULL)
1241*71d10453SEric Joyner  * @name: name of the label to search for
1242*71d10453SEric Joyner  * @type: the section type that will contain the label
1243*71d10453SEric Joyner  * @value: pointer to a value that will return the label's value if found
1244*71d10453SEric Joyner  *
1245*71d10453SEric Joyner  * Finds a label's value given the label name and the section type to search.
1246*71d10453SEric Joyner  * The ice_seg parameter must not be NULL since the first call to
1247*71d10453SEric Joyner  * ice_enum_labels requires a pointer to an actual ice_seg structure.
1248*71d10453SEric Joyner  */
1249*71d10453SEric Joyner enum ice_status
1250*71d10453SEric Joyner ice_find_label_value(struct ice_seg *ice_seg, char const *name, u32 type,
1251*71d10453SEric Joyner 		     u16 *value)
1252*71d10453SEric Joyner {
1253*71d10453SEric Joyner 	struct ice_pkg_enum state;
1254*71d10453SEric Joyner 	char *label_name;
1255*71d10453SEric Joyner 	u16 val;
1256*71d10453SEric Joyner 
1257*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
1258*71d10453SEric Joyner 
1259*71d10453SEric Joyner 	if (!ice_seg)
1260*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1261*71d10453SEric Joyner 
1262*71d10453SEric Joyner 	do {
1263*71d10453SEric Joyner 		label_name = ice_enum_labels(ice_seg, type, &state, &val);
1264*71d10453SEric Joyner 		if (label_name && !strcmp(label_name, name)) {
1265*71d10453SEric Joyner 			*value = val;
1266*71d10453SEric Joyner 			return ICE_SUCCESS;
1267*71d10453SEric Joyner 		}
1268*71d10453SEric Joyner 
1269*71d10453SEric Joyner 		ice_seg = NULL;
1270*71d10453SEric Joyner 	} while (label_name);
1271*71d10453SEric Joyner 
1272*71d10453SEric Joyner 	return ICE_ERR_CFG;
1273*71d10453SEric Joyner }
1274*71d10453SEric Joyner 
1275*71d10453SEric Joyner /**
1276*71d10453SEric Joyner  * ice_verify_pkg - verify package
1277*71d10453SEric Joyner  * @pkg: pointer to the package buffer
1278*71d10453SEric Joyner  * @len: size of the package buffer
1279*71d10453SEric Joyner  *
1280*71d10453SEric Joyner  * Verifies various attributes of the package file, including length, format
1281*71d10453SEric Joyner  * version, and the requirement of at least one segment.
1282*71d10453SEric Joyner  */
1283*71d10453SEric Joyner static enum ice_status ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
1284*71d10453SEric Joyner {
1285*71d10453SEric Joyner 	u32 seg_count;
1286*71d10453SEric Joyner 	u32 i;
1287*71d10453SEric Joyner 
1288*71d10453SEric Joyner 	if (len < sizeof(*pkg))
1289*71d10453SEric Joyner 		return ICE_ERR_BUF_TOO_SHORT;
1290*71d10453SEric Joyner 
1291*71d10453SEric Joyner 	if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
1292*71d10453SEric Joyner 	    pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
1293*71d10453SEric Joyner 	    pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
1294*71d10453SEric Joyner 	    pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
1295*71d10453SEric Joyner 		return ICE_ERR_CFG;
1296*71d10453SEric Joyner 
1297*71d10453SEric Joyner 	/* pkg must have at least one segment */
1298*71d10453SEric Joyner 	seg_count = LE32_TO_CPU(pkg->seg_count);
1299*71d10453SEric Joyner 	if (seg_count < 1)
1300*71d10453SEric Joyner 		return ICE_ERR_CFG;
1301*71d10453SEric Joyner 
1302*71d10453SEric Joyner 	/* make sure segment array fits in package length */
1303*71d10453SEric Joyner 	if (len < ice_struct_size(pkg, seg_offset, seg_count - 1))
1304*71d10453SEric Joyner 		return ICE_ERR_BUF_TOO_SHORT;
1305*71d10453SEric Joyner 
1306*71d10453SEric Joyner 	/* all segments must fit within length */
1307*71d10453SEric Joyner 	for (i = 0; i < seg_count; i++) {
1308*71d10453SEric Joyner 		u32 off = LE32_TO_CPU(pkg->seg_offset[i]);
1309*71d10453SEric Joyner 		struct ice_generic_seg_hdr *seg;
1310*71d10453SEric Joyner 
1311*71d10453SEric Joyner 		/* segment header must fit */
1312*71d10453SEric Joyner 		if (len < off + sizeof(*seg))
1313*71d10453SEric Joyner 			return ICE_ERR_BUF_TOO_SHORT;
1314*71d10453SEric Joyner 
1315*71d10453SEric Joyner 		seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
1316*71d10453SEric Joyner 
1317*71d10453SEric Joyner 		/* segment body must fit */
1318*71d10453SEric Joyner 		if (len < off + LE32_TO_CPU(seg->seg_size))
1319*71d10453SEric Joyner 			return ICE_ERR_BUF_TOO_SHORT;
1320*71d10453SEric Joyner 	}
1321*71d10453SEric Joyner 
1322*71d10453SEric Joyner 	return ICE_SUCCESS;
1323*71d10453SEric Joyner }
1324*71d10453SEric Joyner 
1325*71d10453SEric Joyner /**
1326*71d10453SEric Joyner  * ice_free_seg - free package segment pointer
1327*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1328*71d10453SEric Joyner  *
1329*71d10453SEric Joyner  * Frees the package segment pointer in the proper manner, depending on if the
1330*71d10453SEric Joyner  * segment was allocated or just the passed in pointer was stored.
1331*71d10453SEric Joyner  */
1332*71d10453SEric Joyner void ice_free_seg(struct ice_hw *hw)
1333*71d10453SEric Joyner {
1334*71d10453SEric Joyner 	if (hw->pkg_copy) {
1335*71d10453SEric Joyner 		ice_free(hw, hw->pkg_copy);
1336*71d10453SEric Joyner 		hw->pkg_copy = NULL;
1337*71d10453SEric Joyner 		hw->pkg_size = 0;
1338*71d10453SEric Joyner 	}
1339*71d10453SEric Joyner 	hw->seg = NULL;
1340*71d10453SEric Joyner }
1341*71d10453SEric Joyner 
1342*71d10453SEric Joyner /**
1343*71d10453SEric Joyner  * ice_init_pkg_regs - initialize additional package registers
1344*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1345*71d10453SEric Joyner  */
1346*71d10453SEric Joyner static void ice_init_pkg_regs(struct ice_hw *hw)
1347*71d10453SEric Joyner {
1348*71d10453SEric Joyner #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
1349*71d10453SEric Joyner #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
1350*71d10453SEric Joyner #define ICE_SW_BLK_IDX	0
1351*71d10453SEric Joyner 
1352*71d10453SEric Joyner 	/* setup Switch block input mask, which is 48-bits in two parts */
1353*71d10453SEric Joyner 	wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
1354*71d10453SEric Joyner 	wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
1355*71d10453SEric Joyner }
1356*71d10453SEric Joyner 
1357*71d10453SEric Joyner /**
1358*71d10453SEric Joyner  * ice_chk_pkg_version - check package version for compatibility with driver
1359*71d10453SEric Joyner  * @pkg_ver: pointer to a version structure to check
1360*71d10453SEric Joyner  *
1361*71d10453SEric Joyner  * Check to make sure that the package about to be downloaded is compatible with
1362*71d10453SEric Joyner  * the driver. To be compatible, the major and minor components of the package
1363*71d10453SEric Joyner  * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR
1364*71d10453SEric Joyner  * definitions.
1365*71d10453SEric Joyner  */
1366*71d10453SEric Joyner static enum ice_status ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
1367*71d10453SEric Joyner {
1368*71d10453SEric Joyner 	if (pkg_ver->major != ICE_PKG_SUPP_VER_MAJ ||
1369*71d10453SEric Joyner 	    pkg_ver->minor != ICE_PKG_SUPP_VER_MNR)
1370*71d10453SEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
1371*71d10453SEric Joyner 
1372*71d10453SEric Joyner 	return ICE_SUCCESS;
1373*71d10453SEric Joyner }
1374*71d10453SEric Joyner 
1375*71d10453SEric Joyner /**
1376*71d10453SEric Joyner  * ice_chk_pkg_compat
1377*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1378*71d10453SEric Joyner  * @ospkg: pointer to the package hdr
1379*71d10453SEric Joyner  * @seg: pointer to the package segment hdr
1380*71d10453SEric Joyner  *
1381*71d10453SEric Joyner  * This function checks the package version compatibility with driver and NVM
1382*71d10453SEric Joyner  */
1383*71d10453SEric Joyner static enum ice_status
1384*71d10453SEric Joyner ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr *ospkg,
1385*71d10453SEric Joyner 		   struct ice_seg **seg)
1386*71d10453SEric Joyner {
1387*71d10453SEric Joyner 	struct ice_aqc_get_pkg_info_resp *pkg;
1388*71d10453SEric Joyner 	enum ice_status status;
1389*71d10453SEric Joyner 	u16 size;
1390*71d10453SEric Joyner 	u32 i;
1391*71d10453SEric Joyner 
1392*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
1393*71d10453SEric Joyner 
1394*71d10453SEric Joyner 	/* Check package version compatibility */
1395*71d10453SEric Joyner 	status = ice_chk_pkg_version(&hw->pkg_ver);
1396*71d10453SEric Joyner 	if (status) {
1397*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
1398*71d10453SEric Joyner 		return status;
1399*71d10453SEric Joyner 	}
1400*71d10453SEric Joyner 
1401*71d10453SEric Joyner 	/* find ICE segment in given package */
1402*71d10453SEric Joyner 	*seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE,
1403*71d10453SEric Joyner 						     ospkg);
1404*71d10453SEric Joyner 	if (!*seg) {
1405*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
1406*71d10453SEric Joyner 		return ICE_ERR_CFG;
1407*71d10453SEric Joyner 	}
1408*71d10453SEric Joyner 
1409*71d10453SEric Joyner 	/* Check if FW is compatible with the OS package */
1410*71d10453SEric Joyner 	size = ice_struct_size(pkg, pkg_info, ICE_PKG_CNT - 1);
1411*71d10453SEric Joyner 	pkg = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
1412*71d10453SEric Joyner 	if (!pkg)
1413*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
1414*71d10453SEric Joyner 
1415*71d10453SEric Joyner 	status = ice_aq_get_pkg_info_list(hw, pkg, size, NULL);
1416*71d10453SEric Joyner 	if (status)
1417*71d10453SEric Joyner 		goto fw_ddp_compat_free_alloc;
1418*71d10453SEric Joyner 
1419*71d10453SEric Joyner 	for (i = 0; i < LE32_TO_CPU(pkg->count); i++) {
1420*71d10453SEric Joyner 		/* loop till we find the NVM package */
1421*71d10453SEric Joyner 		if (!pkg->pkg_info[i].is_in_nvm)
1422*71d10453SEric Joyner 			continue;
1423*71d10453SEric Joyner 		if ((*seg)->hdr.seg_format_ver.major !=
1424*71d10453SEric Joyner 			pkg->pkg_info[i].ver.major ||
1425*71d10453SEric Joyner 		    (*seg)->hdr.seg_format_ver.minor >
1426*71d10453SEric Joyner 			pkg->pkg_info[i].ver.minor) {
1427*71d10453SEric Joyner 			status = ICE_ERR_FW_DDP_MISMATCH;
1428*71d10453SEric Joyner 			ice_debug(hw, ICE_DBG_INIT,
1429*71d10453SEric Joyner 				  "OS package is not compatible with NVM.\n");
1430*71d10453SEric Joyner 		}
1431*71d10453SEric Joyner 		/* done processing NVM package so break */
1432*71d10453SEric Joyner 		break;
1433*71d10453SEric Joyner 	}
1434*71d10453SEric Joyner fw_ddp_compat_free_alloc:
1435*71d10453SEric Joyner 	ice_free(hw, pkg);
1436*71d10453SEric Joyner 	return status;
1437*71d10453SEric Joyner }
1438*71d10453SEric Joyner 
1439*71d10453SEric Joyner /**
1440*71d10453SEric Joyner  * ice_init_pkg - initialize/download package
1441*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1442*71d10453SEric Joyner  * @buf: pointer to the package buffer
1443*71d10453SEric Joyner  * @len: size of the package buffer
1444*71d10453SEric Joyner  *
1445*71d10453SEric Joyner  * This function initializes a package. The package contains HW tables
1446*71d10453SEric Joyner  * required to do packet processing. First, the function extracts package
1447*71d10453SEric Joyner  * information such as version. Then it finds the ice configuration segment
1448*71d10453SEric Joyner  * within the package; this function then saves a copy of the segment pointer
1449*71d10453SEric Joyner  * within the supplied package buffer. Next, the function will cache any hints
1450*71d10453SEric Joyner  * from the package, followed by downloading the package itself. Note, that if
1451*71d10453SEric Joyner  * a previous PF driver has already downloaded the package successfully, then
1452*71d10453SEric Joyner  * the current driver will not have to download the package again.
1453*71d10453SEric Joyner  *
1454*71d10453SEric Joyner  * The local package contents will be used to query default behavior and to
1455*71d10453SEric Joyner  * update specific sections of the HW's version of the package (e.g. to update
1456*71d10453SEric Joyner  * the parse graph to understand new protocols).
1457*71d10453SEric Joyner  *
1458*71d10453SEric Joyner  * This function stores a pointer to the package buffer memory, and it is
1459*71d10453SEric Joyner  * expected that the supplied buffer will not be freed immediately. If the
1460*71d10453SEric Joyner  * package buffer needs to be freed, such as when read from a file, use
1461*71d10453SEric Joyner  * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
1462*71d10453SEric Joyner  * case.
1463*71d10453SEric Joyner  */
1464*71d10453SEric Joyner enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
1465*71d10453SEric Joyner {
1466*71d10453SEric Joyner 	struct ice_pkg_hdr *pkg;
1467*71d10453SEric Joyner 	enum ice_status status;
1468*71d10453SEric Joyner 	struct ice_seg *seg;
1469*71d10453SEric Joyner 
1470*71d10453SEric Joyner 	if (!buf || !len)
1471*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1472*71d10453SEric Joyner 
1473*71d10453SEric Joyner 	pkg = (struct ice_pkg_hdr *)buf;
1474*71d10453SEric Joyner 	status = ice_verify_pkg(pkg, len);
1475*71d10453SEric Joyner 	if (status) {
1476*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
1477*71d10453SEric Joyner 			  status);
1478*71d10453SEric Joyner 		return status;
1479*71d10453SEric Joyner 	}
1480*71d10453SEric Joyner 
1481*71d10453SEric Joyner 	/* initialize package info */
1482*71d10453SEric Joyner 	status = ice_init_pkg_info(hw, pkg);
1483*71d10453SEric Joyner 	if (status)
1484*71d10453SEric Joyner 		return status;
1485*71d10453SEric Joyner 
1486*71d10453SEric Joyner 	/* before downloading the package, check package version for
1487*71d10453SEric Joyner 	 * compatibility with driver
1488*71d10453SEric Joyner 	 */
1489*71d10453SEric Joyner 	status = ice_chk_pkg_compat(hw, pkg, &seg);
1490*71d10453SEric Joyner 	if (status)
1491*71d10453SEric Joyner 		return status;
1492*71d10453SEric Joyner 
1493*71d10453SEric Joyner 	/* initialize package hints and then download package */
1494*71d10453SEric Joyner 	ice_init_pkg_hints(hw, seg);
1495*71d10453SEric Joyner 	status = ice_download_pkg(hw, seg);
1496*71d10453SEric Joyner 	if (status == ICE_ERR_AQ_NO_WORK) {
1497*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT,
1498*71d10453SEric Joyner 			  "package previously loaded - no work.\n");
1499*71d10453SEric Joyner 		status = ICE_SUCCESS;
1500*71d10453SEric Joyner 	}
1501*71d10453SEric Joyner 
1502*71d10453SEric Joyner 	/* Get information on the package currently loaded in HW, then make sure
1503*71d10453SEric Joyner 	 * the driver is compatible with this version.
1504*71d10453SEric Joyner 	 */
1505*71d10453SEric Joyner 	if (!status) {
1506*71d10453SEric Joyner 		status = ice_get_pkg_info(hw);
1507*71d10453SEric Joyner 		if (!status)
1508*71d10453SEric Joyner 			status = ice_chk_pkg_version(&hw->active_pkg_ver);
1509*71d10453SEric Joyner 	}
1510*71d10453SEric Joyner 
1511*71d10453SEric Joyner 	if (!status) {
1512*71d10453SEric Joyner 		hw->seg = seg;
1513*71d10453SEric Joyner 		/* on successful package download update other required
1514*71d10453SEric Joyner 		 * registers to support the package and fill HW tables
1515*71d10453SEric Joyner 		 * with package content.
1516*71d10453SEric Joyner 		 */
1517*71d10453SEric Joyner 		ice_init_pkg_regs(hw);
1518*71d10453SEric Joyner 		ice_fill_blk_tbls(hw);
1519*71d10453SEric Joyner 	} else {
1520*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n",
1521*71d10453SEric Joyner 			  status);
1522*71d10453SEric Joyner 	}
1523*71d10453SEric Joyner 
1524*71d10453SEric Joyner 	return status;
1525*71d10453SEric Joyner }
1526*71d10453SEric Joyner 
1527*71d10453SEric Joyner /**
1528*71d10453SEric Joyner  * ice_copy_and_init_pkg - initialize/download a copy of the package
1529*71d10453SEric Joyner  * @hw: pointer to the hardware structure
1530*71d10453SEric Joyner  * @buf: pointer to the package buffer
1531*71d10453SEric Joyner  * @len: size of the package buffer
1532*71d10453SEric Joyner  *
1533*71d10453SEric Joyner  * This function copies the package buffer, and then calls ice_init_pkg() to
1534*71d10453SEric Joyner  * initialize the copied package contents.
1535*71d10453SEric Joyner  *
1536*71d10453SEric Joyner  * The copying is necessary if the package buffer supplied is constant, or if
1537*71d10453SEric Joyner  * the memory may disappear shortly after calling this function.
1538*71d10453SEric Joyner  *
1539*71d10453SEric Joyner  * If the package buffer resides in the data segment and can be modified, the
1540*71d10453SEric Joyner  * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
1541*71d10453SEric Joyner  *
1542*71d10453SEric Joyner  * However, if the package buffer needs to be copied first, such as when being
1543*71d10453SEric Joyner  * read from a file, the caller should use ice_copy_and_init_pkg().
1544*71d10453SEric Joyner  *
1545*71d10453SEric Joyner  * This function will first copy the package buffer, before calling
1546*71d10453SEric Joyner  * ice_init_pkg(). The caller is free to immediately destroy the original
1547*71d10453SEric Joyner  * package buffer, as the new copy will be managed by this function and
1548*71d10453SEric Joyner  * related routines.
1549*71d10453SEric Joyner  */
1550*71d10453SEric Joyner enum ice_status ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len)
1551*71d10453SEric Joyner {
1552*71d10453SEric Joyner 	enum ice_status status;
1553*71d10453SEric Joyner 	u8 *buf_copy;
1554*71d10453SEric Joyner 
1555*71d10453SEric Joyner 	if (!buf || !len)
1556*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1557*71d10453SEric Joyner 
1558*71d10453SEric Joyner 	buf_copy = (u8 *)ice_memdup(hw, buf, len, ICE_NONDMA_TO_NONDMA);
1559*71d10453SEric Joyner 
1560*71d10453SEric Joyner 	status = ice_init_pkg(hw, buf_copy, len);
1561*71d10453SEric Joyner 	if (status) {
1562*71d10453SEric Joyner 		/* Free the copy, since we failed to initialize the package */
1563*71d10453SEric Joyner 		ice_free(hw, buf_copy);
1564*71d10453SEric Joyner 	} else {
1565*71d10453SEric Joyner 		/* Track the copied pkg so we can free it later */
1566*71d10453SEric Joyner 		hw->pkg_copy = buf_copy;
1567*71d10453SEric Joyner 		hw->pkg_size = len;
1568*71d10453SEric Joyner 	}
1569*71d10453SEric Joyner 
1570*71d10453SEric Joyner 	return status;
1571*71d10453SEric Joyner }
1572*71d10453SEric Joyner 
1573*71d10453SEric Joyner /**
1574*71d10453SEric Joyner  * ice_pkg_buf_alloc
1575*71d10453SEric Joyner  * @hw: pointer to the HW structure
1576*71d10453SEric Joyner  *
1577*71d10453SEric Joyner  * Allocates a package buffer and returns a pointer to the buffer header.
1578*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
1579*71d10453SEric Joyner  */
1580*71d10453SEric Joyner static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
1581*71d10453SEric Joyner {
1582*71d10453SEric Joyner 	struct ice_buf_build *bld;
1583*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
1584*71d10453SEric Joyner 
1585*71d10453SEric Joyner 	bld = (struct ice_buf_build *)ice_malloc(hw, sizeof(*bld));
1586*71d10453SEric Joyner 	if (!bld)
1587*71d10453SEric Joyner 		return NULL;
1588*71d10453SEric Joyner 
1589*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)bld;
1590*71d10453SEric Joyner 	buf->data_end = CPU_TO_LE16(offsetof(struct ice_buf_hdr,
1591*71d10453SEric Joyner 					     section_entry));
1592*71d10453SEric Joyner 	return bld;
1593*71d10453SEric Joyner }
1594*71d10453SEric Joyner 
1595*71d10453SEric Joyner /**
1596*71d10453SEric Joyner  * ice_sw_fv_handler
1597*71d10453SEric Joyner  * @sect_type: section type
1598*71d10453SEric Joyner  * @section: pointer to section
1599*71d10453SEric Joyner  * @index: index of the field vector entry to be returned
1600*71d10453SEric Joyner  * @offset: ptr to variable that receives the offset in the field vector table
1601*71d10453SEric Joyner  *
1602*71d10453SEric Joyner  * This is a callback function that can be passed to ice_pkg_enum_entry.
1603*71d10453SEric Joyner  * This function treats the given section as of type ice_sw_fv_section and
1604*71d10453SEric Joyner  * enumerates offset field. "offset" is an index into the field vector
1605*71d10453SEric Joyner  * vector table.
1606*71d10453SEric Joyner  */
1607*71d10453SEric Joyner static void *
1608*71d10453SEric Joyner ice_sw_fv_handler(u32 sect_type, void *section, u32 index, u32 *offset)
1609*71d10453SEric Joyner {
1610*71d10453SEric Joyner 	struct ice_sw_fv_section *fv_section =
1611*71d10453SEric Joyner 		(struct ice_sw_fv_section *)section;
1612*71d10453SEric Joyner 
1613*71d10453SEric Joyner 	if (!section || sect_type != ICE_SID_FLD_VEC_SW)
1614*71d10453SEric Joyner 		return NULL;
1615*71d10453SEric Joyner 	if (index >= LE16_TO_CPU(fv_section->count))
1616*71d10453SEric Joyner 		return NULL;
1617*71d10453SEric Joyner 	if (offset)
1618*71d10453SEric Joyner 		/* "index" passed in to this function is relative to a given
1619*71d10453SEric Joyner 		 * 4k block. To get to the true index into the field vector
1620*71d10453SEric Joyner 		 * table need to add the relative index to the base_offset
1621*71d10453SEric Joyner 		 * field of this section
1622*71d10453SEric Joyner 		 */
1623*71d10453SEric Joyner 		*offset = LE16_TO_CPU(fv_section->base_offset) + index;
1624*71d10453SEric Joyner 	return fv_section->fv + index;
1625*71d10453SEric Joyner }
1626*71d10453SEric Joyner 
1627*71d10453SEric Joyner /**
1628*71d10453SEric Joyner  * ice_get_sw_prof_type - determine switch profile type
1629*71d10453SEric Joyner  * @hw: pointer to the HW structure
1630*71d10453SEric Joyner  * @fv: pointer to the switch field vector
1631*71d10453SEric Joyner  */
1632*71d10453SEric Joyner static enum ice_prof_type
1633*71d10453SEric Joyner ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv)
1634*71d10453SEric Joyner {
1635*71d10453SEric Joyner 	u16 i;
1636*71d10453SEric Joyner 
1637*71d10453SEric Joyner 	for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
1638*71d10453SEric Joyner 		/* UDP tunnel will have UDP_OF protocol ID and VNI offset */
1639*71d10453SEric Joyner 		if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
1640*71d10453SEric Joyner 		    fv->ew[i].off == ICE_VNI_OFFSET)
1641*71d10453SEric Joyner 			return ICE_PROF_TUN_UDP;
1642*71d10453SEric Joyner 
1643*71d10453SEric Joyner 		/* GRE tunnel will have GRE protocol */
1644*71d10453SEric Joyner 		if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
1645*71d10453SEric Joyner 			return ICE_PROF_TUN_GRE;
1646*71d10453SEric Joyner 	}
1647*71d10453SEric Joyner 
1648*71d10453SEric Joyner 	return ICE_PROF_NON_TUN;
1649*71d10453SEric Joyner }
1650*71d10453SEric Joyner 
1651*71d10453SEric Joyner /**
1652*71d10453SEric Joyner  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
1653*71d10453SEric Joyner  * @hw: pointer to hardware structure
1654*71d10453SEric Joyner  * @req_profs: type of profiles requested
1655*71d10453SEric Joyner  * @bm: pointer to memory for returning the bitmap of field vectors
1656*71d10453SEric Joyner  */
1657*71d10453SEric Joyner void
1658*71d10453SEric Joyner ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
1659*71d10453SEric Joyner 		     ice_bitmap_t *bm)
1660*71d10453SEric Joyner {
1661*71d10453SEric Joyner 	struct ice_pkg_enum state;
1662*71d10453SEric Joyner 	struct ice_seg *ice_seg;
1663*71d10453SEric Joyner 	struct ice_fv *fv;
1664*71d10453SEric Joyner 
1665*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
1666*71d10453SEric Joyner 
1667*71d10453SEric Joyner 	if (req_profs == ICE_PROF_ALL) {
1668*71d10453SEric Joyner 		u16 i;
1669*71d10453SEric Joyner 
1670*71d10453SEric Joyner 		for (i = 0; i < ICE_MAX_NUM_PROFILES; i++)
1671*71d10453SEric Joyner 			ice_set_bit(i, bm);
1672*71d10453SEric Joyner 		return;
1673*71d10453SEric Joyner 	}
1674*71d10453SEric Joyner 
1675*71d10453SEric Joyner 	ice_zero_bitmap(bm, ICE_MAX_NUM_PROFILES);
1676*71d10453SEric Joyner 
1677*71d10453SEric Joyner 	ice_seg = hw->seg;
1678*71d10453SEric Joyner 	do {
1679*71d10453SEric Joyner 		enum ice_prof_type prof_type;
1680*71d10453SEric Joyner 		u32 offset;
1681*71d10453SEric Joyner 
1682*71d10453SEric Joyner 		fv = (struct ice_fv *)
1683*71d10453SEric Joyner 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
1684*71d10453SEric Joyner 					   &offset, ice_sw_fv_handler);
1685*71d10453SEric Joyner 		ice_seg = NULL;
1686*71d10453SEric Joyner 
1687*71d10453SEric Joyner 		if (fv) {
1688*71d10453SEric Joyner 			/* Determine field vector type */
1689*71d10453SEric Joyner 			prof_type = ice_get_sw_prof_type(hw, fv);
1690*71d10453SEric Joyner 
1691*71d10453SEric Joyner 			if (req_profs & prof_type)
1692*71d10453SEric Joyner 				ice_set_bit((u16)offset, bm);
1693*71d10453SEric Joyner 		}
1694*71d10453SEric Joyner 	} while (fv);
1695*71d10453SEric Joyner }
1696*71d10453SEric Joyner 
1697*71d10453SEric Joyner /**
1698*71d10453SEric Joyner  * ice_get_sw_fv_list
1699*71d10453SEric Joyner  * @hw: pointer to the HW structure
1700*71d10453SEric Joyner  * @prot_ids: field vector to search for with a given protocol ID
1701*71d10453SEric Joyner  * @ids_cnt: lookup/protocol count
1702*71d10453SEric Joyner  * @bm: bitmap of field vectors to consider
1703*71d10453SEric Joyner  * @fv_list: Head of a list
1704*71d10453SEric Joyner  *
1705*71d10453SEric Joyner  * Finds all the field vector entries from switch block that contain
1706*71d10453SEric Joyner  * a given protocol ID and returns a list of structures of type
1707*71d10453SEric Joyner  * "ice_sw_fv_list_entry". Every structure in the list has a field vector
1708*71d10453SEric Joyner  * definition and profile ID information
1709*71d10453SEric Joyner  * NOTE: The caller of the function is responsible for freeing the memory
1710*71d10453SEric Joyner  * allocated for every list entry.
1711*71d10453SEric Joyner  */
1712*71d10453SEric Joyner enum ice_status
1713*71d10453SEric Joyner ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
1714*71d10453SEric Joyner 		   ice_bitmap_t *bm, struct LIST_HEAD_TYPE *fv_list)
1715*71d10453SEric Joyner {
1716*71d10453SEric Joyner 	struct ice_sw_fv_list_entry *fvl;
1717*71d10453SEric Joyner 	struct ice_sw_fv_list_entry *tmp;
1718*71d10453SEric Joyner 	struct ice_pkg_enum state;
1719*71d10453SEric Joyner 	struct ice_seg *ice_seg;
1720*71d10453SEric Joyner 	struct ice_fv *fv;
1721*71d10453SEric Joyner 	u32 offset;
1722*71d10453SEric Joyner 
1723*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
1724*71d10453SEric Joyner 
1725*71d10453SEric Joyner 	if (!ids_cnt || !hw->seg)
1726*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1727*71d10453SEric Joyner 
1728*71d10453SEric Joyner 	ice_seg = hw->seg;
1729*71d10453SEric Joyner 	do {
1730*71d10453SEric Joyner 		u16 i;
1731*71d10453SEric Joyner 
1732*71d10453SEric Joyner 		fv = (struct ice_fv *)
1733*71d10453SEric Joyner 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
1734*71d10453SEric Joyner 					   &offset, ice_sw_fv_handler);
1735*71d10453SEric Joyner 		if (!fv)
1736*71d10453SEric Joyner 			break;
1737*71d10453SEric Joyner 		ice_seg = NULL;
1738*71d10453SEric Joyner 
1739*71d10453SEric Joyner 		/* If field vector is not in the bitmap list, then skip this
1740*71d10453SEric Joyner 		 * profile.
1741*71d10453SEric Joyner 		 */
1742*71d10453SEric Joyner 		if (!ice_is_bit_set(bm, (u16)offset))
1743*71d10453SEric Joyner 			continue;
1744*71d10453SEric Joyner 
1745*71d10453SEric Joyner 		for (i = 0; i < ids_cnt; i++) {
1746*71d10453SEric Joyner 			int j;
1747*71d10453SEric Joyner 
1748*71d10453SEric Joyner 			/* This code assumes that if a switch field vector line
1749*71d10453SEric Joyner 			 * has a matching protocol, then this line will contain
1750*71d10453SEric Joyner 			 * the entries necessary to represent every field in
1751*71d10453SEric Joyner 			 * that protocol header.
1752*71d10453SEric Joyner 			 */
1753*71d10453SEric Joyner 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
1754*71d10453SEric Joyner 				if (fv->ew[j].prot_id == prot_ids[i])
1755*71d10453SEric Joyner 					break;
1756*71d10453SEric Joyner 			if (j >= hw->blk[ICE_BLK_SW].es.fvw)
1757*71d10453SEric Joyner 				break;
1758*71d10453SEric Joyner 			if (i + 1 == ids_cnt) {
1759*71d10453SEric Joyner 				fvl = (struct ice_sw_fv_list_entry *)
1760*71d10453SEric Joyner 					ice_malloc(hw, sizeof(*fvl));
1761*71d10453SEric Joyner 				if (!fvl)
1762*71d10453SEric Joyner 					goto err;
1763*71d10453SEric Joyner 				fvl->fv_ptr = fv;
1764*71d10453SEric Joyner 				fvl->profile_id = offset;
1765*71d10453SEric Joyner 				LIST_ADD(&fvl->list_entry, fv_list);
1766*71d10453SEric Joyner 				break;
1767*71d10453SEric Joyner 			}
1768*71d10453SEric Joyner 		}
1769*71d10453SEric Joyner 	} while (fv);
1770*71d10453SEric Joyner 	if (LIST_EMPTY(fv_list))
1771*71d10453SEric Joyner 		return ICE_ERR_CFG;
1772*71d10453SEric Joyner 	return ICE_SUCCESS;
1773*71d10453SEric Joyner 
1774*71d10453SEric Joyner err:
1775*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(fvl, tmp, fv_list, ice_sw_fv_list_entry,
1776*71d10453SEric Joyner 				 list_entry) {
1777*71d10453SEric Joyner 		LIST_DEL(&fvl->list_entry);
1778*71d10453SEric Joyner 		ice_free(hw, fvl);
1779*71d10453SEric Joyner 	}
1780*71d10453SEric Joyner 
1781*71d10453SEric Joyner 	return ICE_ERR_NO_MEMORY;
1782*71d10453SEric Joyner }
1783*71d10453SEric Joyner 
1784*71d10453SEric Joyner /**
1785*71d10453SEric Joyner  * ice_init_prof_result_bm - Initialize the profile result index bitmap
1786*71d10453SEric Joyner  * @hw: pointer to hardware structure
1787*71d10453SEric Joyner  */
1788*71d10453SEric Joyner void ice_init_prof_result_bm(struct ice_hw *hw)
1789*71d10453SEric Joyner {
1790*71d10453SEric Joyner 	struct ice_pkg_enum state;
1791*71d10453SEric Joyner 	struct ice_seg *ice_seg;
1792*71d10453SEric Joyner 	struct ice_fv *fv;
1793*71d10453SEric Joyner 
1794*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
1795*71d10453SEric Joyner 
1796*71d10453SEric Joyner 	if (!hw->seg)
1797*71d10453SEric Joyner 		return;
1798*71d10453SEric Joyner 
1799*71d10453SEric Joyner 	ice_seg = hw->seg;
1800*71d10453SEric Joyner 	do {
1801*71d10453SEric Joyner 		u32 off;
1802*71d10453SEric Joyner 		u16 i;
1803*71d10453SEric Joyner 
1804*71d10453SEric Joyner 		fv = (struct ice_fv *)
1805*71d10453SEric Joyner 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
1806*71d10453SEric Joyner 					   &off, ice_sw_fv_handler);
1807*71d10453SEric Joyner 		ice_seg = NULL;
1808*71d10453SEric Joyner 		if (!fv)
1809*71d10453SEric Joyner 			break;
1810*71d10453SEric Joyner 
1811*71d10453SEric Joyner 		ice_zero_bitmap(hw->switch_info->prof_res_bm[off],
1812*71d10453SEric Joyner 				ICE_MAX_FV_WORDS);
1813*71d10453SEric Joyner 
1814*71d10453SEric Joyner 		/* Determine empty field vector indices, these can be
1815*71d10453SEric Joyner 		 * used for recipe results. Skip index 0, since it is
1816*71d10453SEric Joyner 		 * always used for Switch ID.
1817*71d10453SEric Joyner 		 */
1818*71d10453SEric Joyner 		for (i = 1; i < ICE_MAX_FV_WORDS; i++)
1819*71d10453SEric Joyner 			if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
1820*71d10453SEric Joyner 			    fv->ew[i].off == ICE_FV_OFFSET_INVAL)
1821*71d10453SEric Joyner 				ice_set_bit(i,
1822*71d10453SEric Joyner 					    hw->switch_info->prof_res_bm[off]);
1823*71d10453SEric Joyner 	} while (fv);
1824*71d10453SEric Joyner }
1825*71d10453SEric Joyner 
1826*71d10453SEric Joyner /**
1827*71d10453SEric Joyner  * ice_pkg_buf_free
1828*71d10453SEric Joyner  * @hw: pointer to the HW structure
1829*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
1830*71d10453SEric Joyner  *
1831*71d10453SEric Joyner  * Frees a package buffer
1832*71d10453SEric Joyner  */
1833*71d10453SEric Joyner static void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
1834*71d10453SEric Joyner {
1835*71d10453SEric Joyner 	ice_free(hw, bld);
1836*71d10453SEric Joyner }
1837*71d10453SEric Joyner 
1838*71d10453SEric Joyner /**
1839*71d10453SEric Joyner  * ice_pkg_buf_reserve_section
1840*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
1841*71d10453SEric Joyner  * @count: the number of sections to reserve
1842*71d10453SEric Joyner  *
1843*71d10453SEric Joyner  * Reserves one or more section table entries in a package buffer. This routine
1844*71d10453SEric Joyner  * can be called multiple times as long as they are made before calling
1845*71d10453SEric Joyner  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
1846*71d10453SEric Joyner  * is called once, the number of sections that can be allocated will not be able
1847*71d10453SEric Joyner  * to be increased; not using all reserved sections is fine, but this will
1848*71d10453SEric Joyner  * result in some wasted space in the buffer.
1849*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
1850*71d10453SEric Joyner  */
1851*71d10453SEric Joyner static enum ice_status
1852*71d10453SEric Joyner ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
1853*71d10453SEric Joyner {
1854*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
1855*71d10453SEric Joyner 	u16 section_count;
1856*71d10453SEric Joyner 	u16 data_end;
1857*71d10453SEric Joyner 
1858*71d10453SEric Joyner 	if (!bld)
1859*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1860*71d10453SEric Joyner 
1861*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)&bld->buf;
1862*71d10453SEric Joyner 
1863*71d10453SEric Joyner 	/* already an active section, can't increase table size */
1864*71d10453SEric Joyner 	section_count = LE16_TO_CPU(buf->section_count);
1865*71d10453SEric Joyner 	if (section_count > 0)
1866*71d10453SEric Joyner 		return ICE_ERR_CFG;
1867*71d10453SEric Joyner 
1868*71d10453SEric Joyner 	if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT)
1869*71d10453SEric Joyner 		return ICE_ERR_CFG;
1870*71d10453SEric Joyner 	bld->reserved_section_table_entries += count;
1871*71d10453SEric Joyner 
1872*71d10453SEric Joyner 	data_end = LE16_TO_CPU(buf->data_end) +
1873*71d10453SEric Joyner 		   (count * sizeof(buf->section_entry[0]));
1874*71d10453SEric Joyner 	buf->data_end = CPU_TO_LE16(data_end);
1875*71d10453SEric Joyner 
1876*71d10453SEric Joyner 	return ICE_SUCCESS;
1877*71d10453SEric Joyner }
1878*71d10453SEric Joyner 
1879*71d10453SEric Joyner /**
1880*71d10453SEric Joyner  * ice_pkg_buf_alloc_section
1881*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
1882*71d10453SEric Joyner  * @type: the section type value
1883*71d10453SEric Joyner  * @size: the size of the section to reserve (in bytes)
1884*71d10453SEric Joyner  *
1885*71d10453SEric Joyner  * Reserves memory in the buffer for a section's content and updates the
1886*71d10453SEric Joyner  * buffers' status accordingly. This routine returns a pointer to the first
1887*71d10453SEric Joyner  * byte of the section start within the buffer, which is used to fill in the
1888*71d10453SEric Joyner  * section contents.
1889*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
1890*71d10453SEric Joyner  */
1891*71d10453SEric Joyner static void *
1892*71d10453SEric Joyner ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
1893*71d10453SEric Joyner {
1894*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
1895*71d10453SEric Joyner 	u16 sect_count;
1896*71d10453SEric Joyner 	u16 data_end;
1897*71d10453SEric Joyner 
1898*71d10453SEric Joyner 	if (!bld || !type || !size)
1899*71d10453SEric Joyner 		return NULL;
1900*71d10453SEric Joyner 
1901*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)&bld->buf;
1902*71d10453SEric Joyner 
1903*71d10453SEric Joyner 	/* check for enough space left in buffer */
1904*71d10453SEric Joyner 	data_end = LE16_TO_CPU(buf->data_end);
1905*71d10453SEric Joyner 
1906*71d10453SEric Joyner 	/* section start must align on 4 byte boundary */
1907*71d10453SEric Joyner 	data_end = ICE_ALIGN(data_end, 4);
1908*71d10453SEric Joyner 
1909*71d10453SEric Joyner 	if ((data_end + size) > ICE_MAX_S_DATA_END)
1910*71d10453SEric Joyner 		return NULL;
1911*71d10453SEric Joyner 
1912*71d10453SEric Joyner 	/* check for more available section table entries */
1913*71d10453SEric Joyner 	sect_count = LE16_TO_CPU(buf->section_count);
1914*71d10453SEric Joyner 	if (sect_count < bld->reserved_section_table_entries) {
1915*71d10453SEric Joyner 		void *section_ptr = ((u8 *)buf) + data_end;
1916*71d10453SEric Joyner 
1917*71d10453SEric Joyner 		buf->section_entry[sect_count].offset = CPU_TO_LE16(data_end);
1918*71d10453SEric Joyner 		buf->section_entry[sect_count].size = CPU_TO_LE16(size);
1919*71d10453SEric Joyner 		buf->section_entry[sect_count].type = CPU_TO_LE32(type);
1920*71d10453SEric Joyner 
1921*71d10453SEric Joyner 		data_end += size;
1922*71d10453SEric Joyner 		buf->data_end = CPU_TO_LE16(data_end);
1923*71d10453SEric Joyner 
1924*71d10453SEric Joyner 		buf->section_count = CPU_TO_LE16(sect_count + 1);
1925*71d10453SEric Joyner 		return section_ptr;
1926*71d10453SEric Joyner 	}
1927*71d10453SEric Joyner 
1928*71d10453SEric Joyner 	/* no free section table entries */
1929*71d10453SEric Joyner 	return NULL;
1930*71d10453SEric Joyner }
1931*71d10453SEric Joyner 
1932*71d10453SEric Joyner /**
1933*71d10453SEric Joyner  * ice_pkg_buf_alloc_single_section
1934*71d10453SEric Joyner  * @hw: pointer to the HW structure
1935*71d10453SEric Joyner  * @type: the section type value
1936*71d10453SEric Joyner  * @size: the size of the section to reserve (in bytes)
1937*71d10453SEric Joyner  * @section: returns pointer to the section
1938*71d10453SEric Joyner  *
1939*71d10453SEric Joyner  * Allocates a package buffer with a single section.
1940*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
1941*71d10453SEric Joyner  */
1942*71d10453SEric Joyner static struct ice_buf_build *
1943*71d10453SEric Joyner ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size,
1944*71d10453SEric Joyner 				 void **section)
1945*71d10453SEric Joyner {
1946*71d10453SEric Joyner 	struct ice_buf_build *buf;
1947*71d10453SEric Joyner 
1948*71d10453SEric Joyner 	if (!section)
1949*71d10453SEric Joyner 		return NULL;
1950*71d10453SEric Joyner 
1951*71d10453SEric Joyner 	buf = ice_pkg_buf_alloc(hw);
1952*71d10453SEric Joyner 	if (!buf)
1953*71d10453SEric Joyner 		return NULL;
1954*71d10453SEric Joyner 
1955*71d10453SEric Joyner 	if (ice_pkg_buf_reserve_section(buf, 1))
1956*71d10453SEric Joyner 		goto ice_pkg_buf_alloc_single_section_err;
1957*71d10453SEric Joyner 
1958*71d10453SEric Joyner 	*section = ice_pkg_buf_alloc_section(buf, type, size);
1959*71d10453SEric Joyner 	if (!*section)
1960*71d10453SEric Joyner 		goto ice_pkg_buf_alloc_single_section_err;
1961*71d10453SEric Joyner 
1962*71d10453SEric Joyner 	return buf;
1963*71d10453SEric Joyner 
1964*71d10453SEric Joyner ice_pkg_buf_alloc_single_section_err:
1965*71d10453SEric Joyner 	ice_pkg_buf_free(hw, buf);
1966*71d10453SEric Joyner 	return NULL;
1967*71d10453SEric Joyner }
1968*71d10453SEric Joyner 
1969*71d10453SEric Joyner /**
1970*71d10453SEric Joyner  * ice_pkg_buf_unreserve_section
1971*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
1972*71d10453SEric Joyner  * @count: the number of sections to unreserve
1973*71d10453SEric Joyner  *
1974*71d10453SEric Joyner  * Unreserves one or more section table entries in a package buffer, releasing
1975*71d10453SEric Joyner  * space that can be used for section data. This routine can be called
1976*71d10453SEric Joyner  * multiple times as long as they are made before calling
1977*71d10453SEric Joyner  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
1978*71d10453SEric Joyner  * is called once, the number of sections that can be allocated will not be able
1979*71d10453SEric Joyner  * to be increased; not using all reserved sections is fine, but this will
1980*71d10453SEric Joyner  * result in some wasted space in the buffer.
1981*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
1982*71d10453SEric Joyner  */
1983*71d10453SEric Joyner enum ice_status
1984*71d10453SEric Joyner ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count)
1985*71d10453SEric Joyner {
1986*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
1987*71d10453SEric Joyner 	u16 section_count;
1988*71d10453SEric Joyner 	u16 data_end;
1989*71d10453SEric Joyner 
1990*71d10453SEric Joyner 	if (!bld)
1991*71d10453SEric Joyner 		return ICE_ERR_PARAM;
1992*71d10453SEric Joyner 
1993*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)&bld->buf;
1994*71d10453SEric Joyner 
1995*71d10453SEric Joyner 	/* already an active section, can't decrease table size */
1996*71d10453SEric Joyner 	section_count = LE16_TO_CPU(buf->section_count);
1997*71d10453SEric Joyner 	if (section_count > 0)
1998*71d10453SEric Joyner 		return ICE_ERR_CFG;
1999*71d10453SEric Joyner 
2000*71d10453SEric Joyner 	if (count > bld->reserved_section_table_entries)
2001*71d10453SEric Joyner 		return ICE_ERR_CFG;
2002*71d10453SEric Joyner 	bld->reserved_section_table_entries -= count;
2003*71d10453SEric Joyner 
2004*71d10453SEric Joyner 	data_end = LE16_TO_CPU(buf->data_end) -
2005*71d10453SEric Joyner 		   (count * sizeof(buf->section_entry[0]));
2006*71d10453SEric Joyner 	buf->data_end = CPU_TO_LE16(data_end);
2007*71d10453SEric Joyner 
2008*71d10453SEric Joyner 	return ICE_SUCCESS;
2009*71d10453SEric Joyner }
2010*71d10453SEric Joyner 
2011*71d10453SEric Joyner /**
2012*71d10453SEric Joyner  * ice_pkg_buf_get_free_space
2013*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
2014*71d10453SEric Joyner  *
2015*71d10453SEric Joyner  * Returns the number of free bytes remaining in the buffer.
2016*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
2017*71d10453SEric Joyner  */
2018*71d10453SEric Joyner u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld)
2019*71d10453SEric Joyner {
2020*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
2021*71d10453SEric Joyner 
2022*71d10453SEric Joyner 	if (!bld)
2023*71d10453SEric Joyner 		return 0;
2024*71d10453SEric Joyner 
2025*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)&bld->buf;
2026*71d10453SEric Joyner 	return ICE_MAX_S_DATA_END - LE16_TO_CPU(buf->data_end);
2027*71d10453SEric Joyner }
2028*71d10453SEric Joyner 
2029*71d10453SEric Joyner /**
2030*71d10453SEric Joyner  * ice_pkg_buf_get_active_sections
2031*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
2032*71d10453SEric Joyner  *
2033*71d10453SEric Joyner  * Returns the number of active sections. Before using the package buffer
2034*71d10453SEric Joyner  * in an update package command, the caller should make sure that there is at
2035*71d10453SEric Joyner  * least one active section - otherwise, the buffer is not legal and should
2036*71d10453SEric Joyner  * not be used.
2037*71d10453SEric Joyner  * Note: all package contents must be in Little Endian form.
2038*71d10453SEric Joyner  */
2039*71d10453SEric Joyner static u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
2040*71d10453SEric Joyner {
2041*71d10453SEric Joyner 	struct ice_buf_hdr *buf;
2042*71d10453SEric Joyner 
2043*71d10453SEric Joyner 	if (!bld)
2044*71d10453SEric Joyner 		return 0;
2045*71d10453SEric Joyner 
2046*71d10453SEric Joyner 	buf = (struct ice_buf_hdr *)&bld->buf;
2047*71d10453SEric Joyner 	return LE16_TO_CPU(buf->section_count);
2048*71d10453SEric Joyner }
2049*71d10453SEric Joyner 
2050*71d10453SEric Joyner /**
2051*71d10453SEric Joyner  * ice_pkg_buf
2052*71d10453SEric Joyner  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
2053*71d10453SEric Joyner  *
2054*71d10453SEric Joyner  * Return a pointer to the buffer's header
2055*71d10453SEric Joyner  */
2056*71d10453SEric Joyner static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
2057*71d10453SEric Joyner {
2058*71d10453SEric Joyner 	if (!bld)
2059*71d10453SEric Joyner 		return NULL;
2060*71d10453SEric Joyner 
2061*71d10453SEric Joyner 	return &bld->buf;
2062*71d10453SEric Joyner }
2063*71d10453SEric Joyner 
2064*71d10453SEric Joyner /**
2065*71d10453SEric Joyner  * ice_tunnel_port_in_use_hlpr - helper function to determine tunnel usage
2066*71d10453SEric Joyner  * @hw: pointer to the HW structure
2067*71d10453SEric Joyner  * @port: port to search for
2068*71d10453SEric Joyner  * @index: optionally returns index
2069*71d10453SEric Joyner  *
2070*71d10453SEric Joyner  * Returns whether a port is already in use as a tunnel, and optionally its
2071*71d10453SEric Joyner  * index
2072*71d10453SEric Joyner  */
2073*71d10453SEric Joyner static bool ice_tunnel_port_in_use_hlpr(struct ice_hw *hw, u16 port, u16 *index)
2074*71d10453SEric Joyner {
2075*71d10453SEric Joyner 	u16 i;
2076*71d10453SEric Joyner 
2077*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2078*71d10453SEric Joyner 		if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) {
2079*71d10453SEric Joyner 			if (index)
2080*71d10453SEric Joyner 				*index = i;
2081*71d10453SEric Joyner 			return true;
2082*71d10453SEric Joyner 		}
2083*71d10453SEric Joyner 
2084*71d10453SEric Joyner 	return false;
2085*71d10453SEric Joyner }
2086*71d10453SEric Joyner 
2087*71d10453SEric Joyner /**
2088*71d10453SEric Joyner  * ice_tunnel_port_in_use
2089*71d10453SEric Joyner  * @hw: pointer to the HW structure
2090*71d10453SEric Joyner  * @port: port to search for
2091*71d10453SEric Joyner  * @index: optionally returns index
2092*71d10453SEric Joyner  *
2093*71d10453SEric Joyner  * Returns whether a port is already in use as a tunnel, and optionally its
2094*71d10453SEric Joyner  * index
2095*71d10453SEric Joyner  */
2096*71d10453SEric Joyner bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
2097*71d10453SEric Joyner {
2098*71d10453SEric Joyner 	bool res;
2099*71d10453SEric Joyner 
2100*71d10453SEric Joyner 	ice_acquire_lock(&hw->tnl_lock);
2101*71d10453SEric Joyner 	res = ice_tunnel_port_in_use_hlpr(hw, port, index);
2102*71d10453SEric Joyner 	ice_release_lock(&hw->tnl_lock);
2103*71d10453SEric Joyner 
2104*71d10453SEric Joyner 	return res;
2105*71d10453SEric Joyner }
2106*71d10453SEric Joyner 
2107*71d10453SEric Joyner /**
2108*71d10453SEric Joyner  * ice_tunnel_get_type
2109*71d10453SEric Joyner  * @hw: pointer to the HW structure
2110*71d10453SEric Joyner  * @port: port to search for
2111*71d10453SEric Joyner  * @type: returns tunnel index
2112*71d10453SEric Joyner  *
2113*71d10453SEric Joyner  * For a given port number, will return the type of tunnel.
2114*71d10453SEric Joyner  */
2115*71d10453SEric Joyner bool
2116*71d10453SEric Joyner ice_tunnel_get_type(struct ice_hw *hw, u16 port, enum ice_tunnel_type *type)
2117*71d10453SEric Joyner {
2118*71d10453SEric Joyner 	bool res = false;
2119*71d10453SEric Joyner 	u16 i;
2120*71d10453SEric Joyner 
2121*71d10453SEric Joyner 	ice_acquire_lock(&hw->tnl_lock);
2122*71d10453SEric Joyner 
2123*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2124*71d10453SEric Joyner 		if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) {
2125*71d10453SEric Joyner 			*type = hw->tnl.tbl[i].type;
2126*71d10453SEric Joyner 			res = true;
2127*71d10453SEric Joyner 			break;
2128*71d10453SEric Joyner 		}
2129*71d10453SEric Joyner 
2130*71d10453SEric Joyner 	ice_release_lock(&hw->tnl_lock);
2131*71d10453SEric Joyner 
2132*71d10453SEric Joyner 	return res;
2133*71d10453SEric Joyner }
2134*71d10453SEric Joyner 
2135*71d10453SEric Joyner /**
2136*71d10453SEric Joyner  * ice_find_free_tunnel_entry
2137*71d10453SEric Joyner  * @hw: pointer to the HW structure
2138*71d10453SEric Joyner  * @type: tunnel type
2139*71d10453SEric Joyner  * @index: optionally returns index
2140*71d10453SEric Joyner  *
2141*71d10453SEric Joyner  * Returns whether there is a free tunnel entry, and optionally its index
2142*71d10453SEric Joyner  */
2143*71d10453SEric Joyner static bool
2144*71d10453SEric Joyner ice_find_free_tunnel_entry(struct ice_hw *hw, enum ice_tunnel_type type,
2145*71d10453SEric Joyner 			   u16 *index)
2146*71d10453SEric Joyner {
2147*71d10453SEric Joyner 	u16 i;
2148*71d10453SEric Joyner 
2149*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2150*71d10453SEric Joyner 		if (hw->tnl.tbl[i].valid && !hw->tnl.tbl[i].in_use &&
2151*71d10453SEric Joyner 		    hw->tnl.tbl[i].type == type) {
2152*71d10453SEric Joyner 			if (index)
2153*71d10453SEric Joyner 				*index = i;
2154*71d10453SEric Joyner 			return true;
2155*71d10453SEric Joyner 		}
2156*71d10453SEric Joyner 
2157*71d10453SEric Joyner 	return false;
2158*71d10453SEric Joyner }
2159*71d10453SEric Joyner 
2160*71d10453SEric Joyner /**
2161*71d10453SEric Joyner  * ice_get_open_tunnel_port - retrieve an open tunnel port
2162*71d10453SEric Joyner  * @hw: pointer to the HW structure
2163*71d10453SEric Joyner  * @type: tunnel type (TNL_ALL will return any open port)
2164*71d10453SEric Joyner  * @port: returns open port
2165*71d10453SEric Joyner  */
2166*71d10453SEric Joyner bool
2167*71d10453SEric Joyner ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type,
2168*71d10453SEric Joyner 			 u16 *port)
2169*71d10453SEric Joyner {
2170*71d10453SEric Joyner 	bool res = false;
2171*71d10453SEric Joyner 	u16 i;
2172*71d10453SEric Joyner 
2173*71d10453SEric Joyner 	ice_acquire_lock(&hw->tnl_lock);
2174*71d10453SEric Joyner 
2175*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2176*71d10453SEric Joyner 		if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
2177*71d10453SEric Joyner 		    (type == TNL_ALL || hw->tnl.tbl[i].type == type)) {
2178*71d10453SEric Joyner 			*port = hw->tnl.tbl[i].port;
2179*71d10453SEric Joyner 			res = true;
2180*71d10453SEric Joyner 			break;
2181*71d10453SEric Joyner 		}
2182*71d10453SEric Joyner 
2183*71d10453SEric Joyner 	ice_release_lock(&hw->tnl_lock);
2184*71d10453SEric Joyner 
2185*71d10453SEric Joyner 	return res;
2186*71d10453SEric Joyner }
2187*71d10453SEric Joyner 
2188*71d10453SEric Joyner /**
2189*71d10453SEric Joyner  * ice_create_tunnel
2190*71d10453SEric Joyner  * @hw: pointer to the HW structure
2191*71d10453SEric Joyner  * @type: type of tunnel
2192*71d10453SEric Joyner  * @port: port of tunnel to create
2193*71d10453SEric Joyner  *
2194*71d10453SEric Joyner  * Create a tunnel by updating the parse graph in the parser. We do that by
2195*71d10453SEric Joyner  * creating a package buffer with the tunnel info and issuing an update package
2196*71d10453SEric Joyner  * command.
2197*71d10453SEric Joyner  */
2198*71d10453SEric Joyner enum ice_status
2199*71d10453SEric Joyner ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
2200*71d10453SEric Joyner {
2201*71d10453SEric Joyner 	struct ice_boost_tcam_section *sect_rx, *sect_tx;
2202*71d10453SEric Joyner 	enum ice_status status = ICE_ERR_MAX_LIMIT;
2203*71d10453SEric Joyner 	struct ice_buf_build *bld;
2204*71d10453SEric Joyner 	u16 index;
2205*71d10453SEric Joyner 
2206*71d10453SEric Joyner 	ice_acquire_lock(&hw->tnl_lock);
2207*71d10453SEric Joyner 
2208*71d10453SEric Joyner 	if (ice_tunnel_port_in_use_hlpr(hw, port, &index)) {
2209*71d10453SEric Joyner 		hw->tnl.tbl[index].ref++;
2210*71d10453SEric Joyner 		status = ICE_SUCCESS;
2211*71d10453SEric Joyner 		goto ice_create_tunnel_end;
2212*71d10453SEric Joyner 	}
2213*71d10453SEric Joyner 
2214*71d10453SEric Joyner 	if (!ice_find_free_tunnel_entry(hw, type, &index)) {
2215*71d10453SEric Joyner 		status = ICE_ERR_OUT_OF_RANGE;
2216*71d10453SEric Joyner 		goto ice_create_tunnel_end;
2217*71d10453SEric Joyner 	}
2218*71d10453SEric Joyner 
2219*71d10453SEric Joyner 	bld = ice_pkg_buf_alloc(hw);
2220*71d10453SEric Joyner 	if (!bld) {
2221*71d10453SEric Joyner 		status = ICE_ERR_NO_MEMORY;
2222*71d10453SEric Joyner 		goto ice_create_tunnel_end;
2223*71d10453SEric Joyner 	}
2224*71d10453SEric Joyner 
2225*71d10453SEric Joyner 	/* allocate 2 sections, one for Rx parser, one for Tx parser */
2226*71d10453SEric Joyner 	if (ice_pkg_buf_reserve_section(bld, 2))
2227*71d10453SEric Joyner 		goto ice_create_tunnel_err;
2228*71d10453SEric Joyner 
2229*71d10453SEric Joyner 	sect_rx = (struct ice_boost_tcam_section *)
2230*71d10453SEric Joyner 		ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM,
2231*71d10453SEric Joyner 					  sizeof(*sect_rx));
2232*71d10453SEric Joyner 	if (!sect_rx)
2233*71d10453SEric Joyner 		goto ice_create_tunnel_err;
2234*71d10453SEric Joyner 	sect_rx->count = CPU_TO_LE16(1);
2235*71d10453SEric Joyner 
2236*71d10453SEric Joyner 	sect_tx = (struct ice_boost_tcam_section *)
2237*71d10453SEric Joyner 		ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM,
2238*71d10453SEric Joyner 					  sizeof(*sect_tx));
2239*71d10453SEric Joyner 	if (!sect_tx)
2240*71d10453SEric Joyner 		goto ice_create_tunnel_err;
2241*71d10453SEric Joyner 	sect_tx->count = CPU_TO_LE16(1);
2242*71d10453SEric Joyner 
2243*71d10453SEric Joyner 	/* copy original boost entry to update package buffer */
2244*71d10453SEric Joyner 	ice_memcpy(sect_rx->tcam, hw->tnl.tbl[index].boost_entry,
2245*71d10453SEric Joyner 		   sizeof(*sect_rx->tcam), ICE_NONDMA_TO_NONDMA);
2246*71d10453SEric Joyner 
2247*71d10453SEric Joyner 	/* over-write the never-match dest port key bits with the encoded port
2248*71d10453SEric Joyner 	 * bits
2249*71d10453SEric Joyner 	 */
2250*71d10453SEric Joyner 	ice_set_key((u8 *)&sect_rx->tcam[0].key, sizeof(sect_rx->tcam[0].key),
2251*71d10453SEric Joyner 		    (u8 *)&port, NULL, NULL, NULL,
2252*71d10453SEric Joyner 		    (u16)offsetof(struct ice_boost_key_value, hv_dst_port_key),
2253*71d10453SEric Joyner 		    sizeof(sect_rx->tcam[0].key.key.hv_dst_port_key));
2254*71d10453SEric Joyner 
2255*71d10453SEric Joyner 	/* exact copy of entry to Tx section entry */
2256*71d10453SEric Joyner 	ice_memcpy(sect_tx->tcam, sect_rx->tcam, sizeof(*sect_tx->tcam),
2257*71d10453SEric Joyner 		   ICE_NONDMA_TO_NONDMA);
2258*71d10453SEric Joyner 
2259*71d10453SEric Joyner 	status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
2260*71d10453SEric Joyner 	if (!status) {
2261*71d10453SEric Joyner 		hw->tnl.tbl[index].port = port;
2262*71d10453SEric Joyner 		hw->tnl.tbl[index].in_use = true;
2263*71d10453SEric Joyner 		hw->tnl.tbl[index].ref = 1;
2264*71d10453SEric Joyner 	}
2265*71d10453SEric Joyner 
2266*71d10453SEric Joyner ice_create_tunnel_err:
2267*71d10453SEric Joyner 	ice_pkg_buf_free(hw, bld);
2268*71d10453SEric Joyner 
2269*71d10453SEric Joyner ice_create_tunnel_end:
2270*71d10453SEric Joyner 	ice_release_lock(&hw->tnl_lock);
2271*71d10453SEric Joyner 
2272*71d10453SEric Joyner 	return status;
2273*71d10453SEric Joyner }
2274*71d10453SEric Joyner 
2275*71d10453SEric Joyner /**
2276*71d10453SEric Joyner  * ice_destroy_tunnel
2277*71d10453SEric Joyner  * @hw: pointer to the HW structure
2278*71d10453SEric Joyner  * @port: port of tunnel to destroy (ignored if the all parameter is true)
2279*71d10453SEric Joyner  * @all: flag that states to destroy all tunnels
2280*71d10453SEric Joyner  *
2281*71d10453SEric Joyner  * Destroys a tunnel or all tunnels by creating an update package buffer
2282*71d10453SEric Joyner  * targeting the specific updates requested and then performing an update
2283*71d10453SEric Joyner  * package.
2284*71d10453SEric Joyner  */
2285*71d10453SEric Joyner enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
2286*71d10453SEric Joyner {
2287*71d10453SEric Joyner 	struct ice_boost_tcam_section *sect_rx, *sect_tx;
2288*71d10453SEric Joyner 	enum ice_status status = ICE_ERR_MAX_LIMIT;
2289*71d10453SEric Joyner 	struct ice_buf_build *bld;
2290*71d10453SEric Joyner 	u16 count = 0;
2291*71d10453SEric Joyner 	u16 index;
2292*71d10453SEric Joyner 	u16 size;
2293*71d10453SEric Joyner 	u16 i;
2294*71d10453SEric Joyner 
2295*71d10453SEric Joyner 	ice_acquire_lock(&hw->tnl_lock);
2296*71d10453SEric Joyner 
2297*71d10453SEric Joyner 	if (!all && ice_tunnel_port_in_use_hlpr(hw, port, &index))
2298*71d10453SEric Joyner 		if (hw->tnl.tbl[index].ref > 1) {
2299*71d10453SEric Joyner 			hw->tnl.tbl[index].ref--;
2300*71d10453SEric Joyner 			status = ICE_SUCCESS;
2301*71d10453SEric Joyner 			goto ice_destroy_tunnel_end;
2302*71d10453SEric Joyner 		}
2303*71d10453SEric Joyner 
2304*71d10453SEric Joyner 	/* determine count */
2305*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2306*71d10453SEric Joyner 		if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
2307*71d10453SEric Joyner 		    (all || hw->tnl.tbl[i].port == port))
2308*71d10453SEric Joyner 			count++;
2309*71d10453SEric Joyner 
2310*71d10453SEric Joyner 	if (!count) {
2311*71d10453SEric Joyner 		status = ICE_ERR_PARAM;
2312*71d10453SEric Joyner 		goto ice_destroy_tunnel_end;
2313*71d10453SEric Joyner 	}
2314*71d10453SEric Joyner 
2315*71d10453SEric Joyner 	/* size of section - there is at least one entry */
2316*71d10453SEric Joyner 	size = ice_struct_size(sect_rx, tcam, count - 1);
2317*71d10453SEric Joyner 
2318*71d10453SEric Joyner 	bld = ice_pkg_buf_alloc(hw);
2319*71d10453SEric Joyner 	if (!bld) {
2320*71d10453SEric Joyner 		status = ICE_ERR_NO_MEMORY;
2321*71d10453SEric Joyner 		goto ice_destroy_tunnel_end;
2322*71d10453SEric Joyner 	}
2323*71d10453SEric Joyner 
2324*71d10453SEric Joyner 	/* allocate 2 sections, one for Rx parser, one for Tx parser */
2325*71d10453SEric Joyner 	if (ice_pkg_buf_reserve_section(bld, 2))
2326*71d10453SEric Joyner 		goto ice_destroy_tunnel_err;
2327*71d10453SEric Joyner 
2328*71d10453SEric Joyner 	sect_rx = (struct ice_boost_tcam_section *)
2329*71d10453SEric Joyner 		ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM,
2330*71d10453SEric Joyner 					  size);
2331*71d10453SEric Joyner 	if (!sect_rx)
2332*71d10453SEric Joyner 		goto ice_destroy_tunnel_err;
2333*71d10453SEric Joyner 	sect_rx->count = CPU_TO_LE16(1);
2334*71d10453SEric Joyner 
2335*71d10453SEric Joyner 	sect_tx = (struct ice_boost_tcam_section *)
2336*71d10453SEric Joyner 		ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM,
2337*71d10453SEric Joyner 					  size);
2338*71d10453SEric Joyner 	if (!sect_tx)
2339*71d10453SEric Joyner 		goto ice_destroy_tunnel_err;
2340*71d10453SEric Joyner 	sect_tx->count = CPU_TO_LE16(1);
2341*71d10453SEric Joyner 
2342*71d10453SEric Joyner 	/* copy original boost entry to update package buffer, one copy to Rx
2343*71d10453SEric Joyner 	 * section, another copy to the Tx section
2344*71d10453SEric Joyner 	 */
2345*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
2346*71d10453SEric Joyner 		if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
2347*71d10453SEric Joyner 		    (all || hw->tnl.tbl[i].port == port)) {
2348*71d10453SEric Joyner 			ice_memcpy(sect_rx->tcam + i,
2349*71d10453SEric Joyner 				   hw->tnl.tbl[i].boost_entry,
2350*71d10453SEric Joyner 				   sizeof(*sect_rx->tcam),
2351*71d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
2352*71d10453SEric Joyner 			ice_memcpy(sect_tx->tcam + i,
2353*71d10453SEric Joyner 				   hw->tnl.tbl[i].boost_entry,
2354*71d10453SEric Joyner 				   sizeof(*sect_tx->tcam),
2355*71d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
2356*71d10453SEric Joyner 			hw->tnl.tbl[i].marked = true;
2357*71d10453SEric Joyner 		}
2358*71d10453SEric Joyner 
2359*71d10453SEric Joyner 	status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
2360*71d10453SEric Joyner 	if (!status)
2361*71d10453SEric Joyner 		for (i = 0; i < hw->tnl.count &&
2362*71d10453SEric Joyner 		     i < ICE_TUNNEL_MAX_ENTRIES; i++)
2363*71d10453SEric Joyner 			if (hw->tnl.tbl[i].marked) {
2364*71d10453SEric Joyner 				hw->tnl.tbl[i].ref = 0;
2365*71d10453SEric Joyner 				hw->tnl.tbl[i].port = 0;
2366*71d10453SEric Joyner 				hw->tnl.tbl[i].in_use = false;
2367*71d10453SEric Joyner 				hw->tnl.tbl[i].marked = false;
2368*71d10453SEric Joyner 			}
2369*71d10453SEric Joyner 
2370*71d10453SEric Joyner ice_destroy_tunnel_err:
2371*71d10453SEric Joyner 	ice_pkg_buf_free(hw, bld);
2372*71d10453SEric Joyner 
2373*71d10453SEric Joyner ice_destroy_tunnel_end:
2374*71d10453SEric Joyner 	ice_release_lock(&hw->tnl_lock);
2375*71d10453SEric Joyner 
2376*71d10453SEric Joyner 	return status;
2377*71d10453SEric Joyner }
2378*71d10453SEric Joyner 
2379*71d10453SEric Joyner /**
2380*71d10453SEric Joyner  * ice_replay_tunnels
2381*71d10453SEric Joyner  * @hw: pointer to the HW structure
2382*71d10453SEric Joyner  *
2383*71d10453SEric Joyner  * Replays all tunnels
2384*71d10453SEric Joyner  */
2385*71d10453SEric Joyner enum ice_status ice_replay_tunnels(struct ice_hw *hw)
2386*71d10453SEric Joyner {
2387*71d10453SEric Joyner 	enum ice_status status = ICE_SUCCESS;
2388*71d10453SEric Joyner 	u16 i;
2389*71d10453SEric Joyner 
2390*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
2391*71d10453SEric Joyner 
2392*71d10453SEric Joyner 	for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) {
2393*71d10453SEric Joyner 		enum ice_tunnel_type type = hw->tnl.tbl[i].type;
2394*71d10453SEric Joyner 		u16 refs = hw->tnl.tbl[i].ref;
2395*71d10453SEric Joyner 		u16 port = hw->tnl.tbl[i].port;
2396*71d10453SEric Joyner 
2397*71d10453SEric Joyner 		if (!hw->tnl.tbl[i].in_use)
2398*71d10453SEric Joyner 			continue;
2399*71d10453SEric Joyner 
2400*71d10453SEric Joyner 		/* Replay tunnels one at a time by destroying them, then
2401*71d10453SEric Joyner 		 * recreating them
2402*71d10453SEric Joyner 		 */
2403*71d10453SEric Joyner 		hw->tnl.tbl[i].ref = 1; /* make sure to destroy in one call */
2404*71d10453SEric Joyner 		status = ice_destroy_tunnel(hw, port, false);
2405*71d10453SEric Joyner 		if (status) {
2406*71d10453SEric Joyner 			ice_debug(hw, ICE_DBG_PKG,
2407*71d10453SEric Joyner 				  "ERR: 0x%x - destroy tunnel port 0x%x\n",
2408*71d10453SEric Joyner 				  status, port);
2409*71d10453SEric Joyner 			break;
2410*71d10453SEric Joyner 		}
2411*71d10453SEric Joyner 
2412*71d10453SEric Joyner 		status = ice_create_tunnel(hw, type, port);
2413*71d10453SEric Joyner 		if (status) {
2414*71d10453SEric Joyner 			ice_debug(hw, ICE_DBG_PKG,
2415*71d10453SEric Joyner 				  "ERR: 0x%x - create tunnel port 0x%x\n",
2416*71d10453SEric Joyner 				  status, port);
2417*71d10453SEric Joyner 			break;
2418*71d10453SEric Joyner 		}
2419*71d10453SEric Joyner 
2420*71d10453SEric Joyner 		/* reset to original ref count */
2421*71d10453SEric Joyner 		hw->tnl.tbl[i].ref = refs;
2422*71d10453SEric Joyner 	}
2423*71d10453SEric Joyner 
2424*71d10453SEric Joyner 	return status;
2425*71d10453SEric Joyner }
2426*71d10453SEric Joyner 
2427*71d10453SEric Joyner /**
2428*71d10453SEric Joyner  * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index
2429*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2430*71d10453SEric Joyner  * @blk: hardware block
2431*71d10453SEric Joyner  * @prof: profile ID
2432*71d10453SEric Joyner  * @fv_idx: field vector word index
2433*71d10453SEric Joyner  * @prot: variable to receive the protocol ID
2434*71d10453SEric Joyner  * @off: variable to receive the protocol offset
2435*71d10453SEric Joyner  */
2436*71d10453SEric Joyner enum ice_status
2437*71d10453SEric Joyner ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
2438*71d10453SEric Joyner 		  u8 *prot, u16 *off)
2439*71d10453SEric Joyner {
2440*71d10453SEric Joyner 	struct ice_fv_word *fv_ext;
2441*71d10453SEric Joyner 
2442*71d10453SEric Joyner 	if (prof >= hw->blk[blk].es.count)
2443*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2444*71d10453SEric Joyner 
2445*71d10453SEric Joyner 	if (fv_idx >= hw->blk[blk].es.fvw)
2446*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2447*71d10453SEric Joyner 
2448*71d10453SEric Joyner 	fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);
2449*71d10453SEric Joyner 
2450*71d10453SEric Joyner 	*prot = fv_ext[fv_idx].prot_id;
2451*71d10453SEric Joyner 	*off = fv_ext[fv_idx].off;
2452*71d10453SEric Joyner 
2453*71d10453SEric Joyner 	return ICE_SUCCESS;
2454*71d10453SEric Joyner }
2455*71d10453SEric Joyner 
2456*71d10453SEric Joyner /* PTG Management */
2457*71d10453SEric Joyner 
2458*71d10453SEric Joyner /**
2459*71d10453SEric Joyner  * ice_ptg_update_xlt1 - Updates packet type groups in HW via XLT1 table
2460*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2461*71d10453SEric Joyner  * @blk: HW block
2462*71d10453SEric Joyner  *
2463*71d10453SEric Joyner  * This function will update the XLT1 hardware table to reflect the new
2464*71d10453SEric Joyner  * packet type group configuration.
2465*71d10453SEric Joyner  */
2466*71d10453SEric Joyner enum ice_status ice_ptg_update_xlt1(struct ice_hw *hw, enum ice_block blk)
2467*71d10453SEric Joyner {
2468*71d10453SEric Joyner 	struct ice_xlt1_section *sect;
2469*71d10453SEric Joyner 	struct ice_buf_build *bld;
2470*71d10453SEric Joyner 	enum ice_status status;
2471*71d10453SEric Joyner 	u16 index;
2472*71d10453SEric Joyner 
2473*71d10453SEric Joyner 	bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT1),
2474*71d10453SEric Joyner 					       ICE_XLT1_SIZE(ICE_XLT1_CNT),
2475*71d10453SEric Joyner 					       (void **)&sect);
2476*71d10453SEric Joyner 	if (!bld)
2477*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
2478*71d10453SEric Joyner 
2479*71d10453SEric Joyner 	sect->count = CPU_TO_LE16(ICE_XLT1_CNT);
2480*71d10453SEric Joyner 	sect->offset = CPU_TO_LE16(0);
2481*71d10453SEric Joyner 	for (index = 0; index < ICE_XLT1_CNT; index++)
2482*71d10453SEric Joyner 		sect->value[index] = hw->blk[blk].xlt1.ptypes[index].ptg;
2483*71d10453SEric Joyner 
2484*71d10453SEric Joyner 	status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
2485*71d10453SEric Joyner 
2486*71d10453SEric Joyner 	ice_pkg_buf_free(hw, bld);
2487*71d10453SEric Joyner 
2488*71d10453SEric Joyner 	return status;
2489*71d10453SEric Joyner }
2490*71d10453SEric Joyner 
2491*71d10453SEric Joyner /**
2492*71d10453SEric Joyner  * ice_ptg_find_ptype - Search for packet type group using packet type (ptype)
2493*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2494*71d10453SEric Joyner  * @blk: HW block
2495*71d10453SEric Joyner  * @ptype: the ptype to search for
2496*71d10453SEric Joyner  * @ptg: pointer to variable that receives the PTG
2497*71d10453SEric Joyner  *
2498*71d10453SEric Joyner  * This function will search the PTGs for a particular ptype, returning the
2499*71d10453SEric Joyner  * PTG ID that contains it through the PTG parameter, with the value of
2500*71d10453SEric Joyner  * ICE_DEFAULT_PTG (0) meaning it is part the default PTG.
2501*71d10453SEric Joyner  */
2502*71d10453SEric Joyner static enum ice_status
2503*71d10453SEric Joyner ice_ptg_find_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg)
2504*71d10453SEric Joyner {
2505*71d10453SEric Joyner 	if (ptype >= ICE_XLT1_CNT || !ptg)
2506*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2507*71d10453SEric Joyner 
2508*71d10453SEric Joyner 	*ptg = hw->blk[blk].xlt1.ptypes[ptype].ptg;
2509*71d10453SEric Joyner 	return ICE_SUCCESS;
2510*71d10453SEric Joyner }
2511*71d10453SEric Joyner 
2512*71d10453SEric Joyner /**
2513*71d10453SEric Joyner  * ice_ptg_alloc_val - Allocates a new packet type group ID by value
2514*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2515*71d10453SEric Joyner  * @blk: HW block
2516*71d10453SEric Joyner  * @ptg: the PTG to allocate
2517*71d10453SEric Joyner  *
2518*71d10453SEric Joyner  * This function allocates a given packet type group ID specified by the PTG
2519*71d10453SEric Joyner  * parameter.
2520*71d10453SEric Joyner  */
2521*71d10453SEric Joyner static void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg)
2522*71d10453SEric Joyner {
2523*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = true;
2524*71d10453SEric Joyner }
2525*71d10453SEric Joyner 
2526*71d10453SEric Joyner /**
2527*71d10453SEric Joyner  * ice_ptg_free - Frees a packet type group
2528*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2529*71d10453SEric Joyner  * @blk: HW block
2530*71d10453SEric Joyner  * @ptg: the PTG ID to free
2531*71d10453SEric Joyner  *
2532*71d10453SEric Joyner  * This function frees a packet type group, and returns all the current ptypes
2533*71d10453SEric Joyner  * within it to the default PTG.
2534*71d10453SEric Joyner  */
2535*71d10453SEric Joyner void ice_ptg_free(struct ice_hw *hw, enum ice_block blk, u8 ptg)
2536*71d10453SEric Joyner {
2537*71d10453SEric Joyner 	struct ice_ptg_ptype *p, *temp;
2538*71d10453SEric Joyner 
2539*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = false;
2540*71d10453SEric Joyner 	p = hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype;
2541*71d10453SEric Joyner 	while (p) {
2542*71d10453SEric Joyner 		p->ptg = ICE_DEFAULT_PTG;
2543*71d10453SEric Joyner 		temp = p->next_ptype;
2544*71d10453SEric Joyner 		p->next_ptype = NULL;
2545*71d10453SEric Joyner 		p = temp;
2546*71d10453SEric Joyner 	}
2547*71d10453SEric Joyner 
2548*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype = NULL;
2549*71d10453SEric Joyner }
2550*71d10453SEric Joyner 
2551*71d10453SEric Joyner /**
2552*71d10453SEric Joyner  * ice_ptg_remove_ptype - Removes ptype from a particular packet type group
2553*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2554*71d10453SEric Joyner  * @blk: HW block
2555*71d10453SEric Joyner  * @ptype: the ptype to remove
2556*71d10453SEric Joyner  * @ptg: the PTG to remove the ptype from
2557*71d10453SEric Joyner  *
2558*71d10453SEric Joyner  * This function will remove the ptype from the specific PTG, and move it to
2559*71d10453SEric Joyner  * the default PTG (ICE_DEFAULT_PTG).
2560*71d10453SEric Joyner  */
2561*71d10453SEric Joyner static enum ice_status
2562*71d10453SEric Joyner ice_ptg_remove_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg)
2563*71d10453SEric Joyner {
2564*71d10453SEric Joyner 	struct ice_ptg_ptype **ch;
2565*71d10453SEric Joyner 	struct ice_ptg_ptype *p;
2566*71d10453SEric Joyner 
2567*71d10453SEric Joyner 	if (ptype > ICE_XLT1_CNT - 1)
2568*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2569*71d10453SEric Joyner 
2570*71d10453SEric Joyner 	if (!hw->blk[blk].xlt1.ptg_tbl[ptg].in_use)
2571*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
2572*71d10453SEric Joyner 
2573*71d10453SEric Joyner 	/* Should not happen if .in_use is set, bad config */
2574*71d10453SEric Joyner 	if (!hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype)
2575*71d10453SEric Joyner 		return ICE_ERR_CFG;
2576*71d10453SEric Joyner 
2577*71d10453SEric Joyner 	/* find the ptype within this PTG, and bypass the link over it */
2578*71d10453SEric Joyner 	p = hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype;
2579*71d10453SEric Joyner 	ch = &hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype;
2580*71d10453SEric Joyner 	while (p) {
2581*71d10453SEric Joyner 		if (ptype == (p - hw->blk[blk].xlt1.ptypes)) {
2582*71d10453SEric Joyner 			*ch = p->next_ptype;
2583*71d10453SEric Joyner 			break;
2584*71d10453SEric Joyner 		}
2585*71d10453SEric Joyner 
2586*71d10453SEric Joyner 		ch = &p->next_ptype;
2587*71d10453SEric Joyner 		p = p->next_ptype;
2588*71d10453SEric Joyner 	}
2589*71d10453SEric Joyner 
2590*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptypes[ptype].ptg = ICE_DEFAULT_PTG;
2591*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptypes[ptype].next_ptype = NULL;
2592*71d10453SEric Joyner 
2593*71d10453SEric Joyner 	return ICE_SUCCESS;
2594*71d10453SEric Joyner }
2595*71d10453SEric Joyner 
2596*71d10453SEric Joyner /**
2597*71d10453SEric Joyner  * ice_ptg_add_mv_ptype - Adds/moves ptype to a particular packet type group
2598*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2599*71d10453SEric Joyner  * @blk: HW block
2600*71d10453SEric Joyner  * @ptype: the ptype to add or move
2601*71d10453SEric Joyner  * @ptg: the PTG to add or move the ptype to
2602*71d10453SEric Joyner  *
2603*71d10453SEric Joyner  * This function will either add or move a ptype to a particular PTG depending
2604*71d10453SEric Joyner  * on if the ptype is already part of another group. Note that using a
2605*71d10453SEric Joyner  * a destination PTG ID of ICE_DEFAULT_PTG (0) will move the ptype to the
2606*71d10453SEric Joyner  * default PTG.
2607*71d10453SEric Joyner  */
2608*71d10453SEric Joyner static enum ice_status
2609*71d10453SEric Joyner ice_ptg_add_mv_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg)
2610*71d10453SEric Joyner {
2611*71d10453SEric Joyner 	enum ice_status status;
2612*71d10453SEric Joyner 	u8 original_ptg;
2613*71d10453SEric Joyner 
2614*71d10453SEric Joyner 	if (ptype > ICE_XLT1_CNT - 1)
2615*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2616*71d10453SEric Joyner 
2617*71d10453SEric Joyner 	if (!hw->blk[blk].xlt1.ptg_tbl[ptg].in_use && ptg != ICE_DEFAULT_PTG)
2618*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
2619*71d10453SEric Joyner 
2620*71d10453SEric Joyner 	status = ice_ptg_find_ptype(hw, blk, ptype, &original_ptg);
2621*71d10453SEric Joyner 	if (status)
2622*71d10453SEric Joyner 		return status;
2623*71d10453SEric Joyner 
2624*71d10453SEric Joyner 	/* Is ptype already in the correct PTG? */
2625*71d10453SEric Joyner 	if (original_ptg == ptg)
2626*71d10453SEric Joyner 		return ICE_SUCCESS;
2627*71d10453SEric Joyner 
2628*71d10453SEric Joyner 	/* Remove from original PTG and move back to the default PTG */
2629*71d10453SEric Joyner 	if (original_ptg != ICE_DEFAULT_PTG)
2630*71d10453SEric Joyner 		ice_ptg_remove_ptype(hw, blk, ptype, original_ptg);
2631*71d10453SEric Joyner 
2632*71d10453SEric Joyner 	/* Moving to default PTG? Then we're done with this request */
2633*71d10453SEric Joyner 	if (ptg == ICE_DEFAULT_PTG)
2634*71d10453SEric Joyner 		return ICE_SUCCESS;
2635*71d10453SEric Joyner 
2636*71d10453SEric Joyner 	/* Add ptype to PTG at beginning of list */
2637*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptypes[ptype].next_ptype =
2638*71d10453SEric Joyner 		hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype;
2639*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype =
2640*71d10453SEric Joyner 		&hw->blk[blk].xlt1.ptypes[ptype];
2641*71d10453SEric Joyner 
2642*71d10453SEric Joyner 	hw->blk[blk].xlt1.ptypes[ptype].ptg = ptg;
2643*71d10453SEric Joyner 	hw->blk[blk].xlt1.t[ptype] = ptg;
2644*71d10453SEric Joyner 
2645*71d10453SEric Joyner 	return ICE_SUCCESS;
2646*71d10453SEric Joyner }
2647*71d10453SEric Joyner 
2648*71d10453SEric Joyner /* Block / table size info */
2649*71d10453SEric Joyner struct ice_blk_size_details {
2650*71d10453SEric Joyner 	u16 xlt1;			/* # XLT1 entries */
2651*71d10453SEric Joyner 	u16 xlt2;			/* # XLT2 entries */
2652*71d10453SEric Joyner 	u16 prof_tcam;			/* # profile ID TCAM entries */
2653*71d10453SEric Joyner 	u16 prof_id;			/* # profile IDs */
2654*71d10453SEric Joyner 	u8 prof_cdid_bits;		/* # CDID one-hot bits used in key */
2655*71d10453SEric Joyner 	u16 prof_redir;			/* # profile redirection entries */
2656*71d10453SEric Joyner 	u16 es;				/* # extraction sequence entries */
2657*71d10453SEric Joyner 	u16 fvw;			/* # field vector words */
2658*71d10453SEric Joyner 	u8 overwrite;			/* overwrite existing entries allowed */
2659*71d10453SEric Joyner 	u8 reverse;			/* reverse FV order */
2660*71d10453SEric Joyner };
2661*71d10453SEric Joyner 
2662*71d10453SEric Joyner static const struct ice_blk_size_details blk_sizes[ICE_BLK_COUNT] = {
2663*71d10453SEric Joyner 	/**
2664*71d10453SEric Joyner 	 * Table Definitions
2665*71d10453SEric Joyner 	 * XLT1 - Number of entries in XLT1 table
2666*71d10453SEric Joyner 	 * XLT2 - Number of entries in XLT2 table
2667*71d10453SEric Joyner 	 * TCAM - Number of entries Profile ID TCAM table
2668*71d10453SEric Joyner 	 * CDID - Control Domain ID of the hardware block
2669*71d10453SEric Joyner 	 * PRED - Number of entries in the Profile Redirection Table
2670*71d10453SEric Joyner 	 * FV   - Number of entries in the Field Vector
2671*71d10453SEric Joyner 	 * FVW  - Width (in WORDs) of the Field Vector
2672*71d10453SEric Joyner 	 * OVR  - Overwrite existing table entries
2673*71d10453SEric Joyner 	 * REV  - Reverse FV
2674*71d10453SEric Joyner 	 */
2675*71d10453SEric Joyner 	/*          XLT1        , XLT2        ,TCAM, PID,CDID,PRED,   FV, FVW */
2676*71d10453SEric Joyner 	/*          Overwrite   , Reverse FV */
2677*71d10453SEric Joyner 	/* SW  */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 256,   0,  256, 256,  48,
2678*71d10453SEric Joyner 		    false, false },
2679*71d10453SEric Joyner 	/* ACL */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128,   0,  128, 128,  32,
2680*71d10453SEric Joyner 		    false, false },
2681*71d10453SEric Joyner 	/* FD  */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128,   0,  128, 128,  24,
2682*71d10453SEric Joyner 		    false, true  },
2683*71d10453SEric Joyner 	/* RSS */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128,   0,  128, 128,  24,
2684*71d10453SEric Joyner 		    true,  true  },
2685*71d10453SEric Joyner 	/* PE  */ { ICE_XLT1_CNT, ICE_XLT2_CNT,  64,  32,   0,   32,  32,  24,
2686*71d10453SEric Joyner 		    false, false },
2687*71d10453SEric Joyner };
2688*71d10453SEric Joyner 
2689*71d10453SEric Joyner enum ice_sid_all {
2690*71d10453SEric Joyner 	ICE_SID_XLT1_OFF = 0,
2691*71d10453SEric Joyner 	ICE_SID_XLT2_OFF,
2692*71d10453SEric Joyner 	ICE_SID_PR_OFF,
2693*71d10453SEric Joyner 	ICE_SID_PR_REDIR_OFF,
2694*71d10453SEric Joyner 	ICE_SID_ES_OFF,
2695*71d10453SEric Joyner 	ICE_SID_OFF_COUNT,
2696*71d10453SEric Joyner };
2697*71d10453SEric Joyner 
2698*71d10453SEric Joyner /* Characteristic handling */
2699*71d10453SEric Joyner 
2700*71d10453SEric Joyner /**
2701*71d10453SEric Joyner  * ice_match_prop_lst - determine if properties of two lists match
2702*71d10453SEric Joyner  * @list1: first properties list
2703*71d10453SEric Joyner  * @list2: second properties list
2704*71d10453SEric Joyner  *
2705*71d10453SEric Joyner  * Count, cookies and the order must match in order to be considered equivalent.
2706*71d10453SEric Joyner  */
2707*71d10453SEric Joyner static bool
2708*71d10453SEric Joyner ice_match_prop_lst(struct LIST_HEAD_TYPE *list1, struct LIST_HEAD_TYPE *list2)
2709*71d10453SEric Joyner {
2710*71d10453SEric Joyner 	struct ice_vsig_prof *tmp1;
2711*71d10453SEric Joyner 	struct ice_vsig_prof *tmp2;
2712*71d10453SEric Joyner 	u16 chk_count = 0;
2713*71d10453SEric Joyner 	u16 count = 0;
2714*71d10453SEric Joyner 
2715*71d10453SEric Joyner 	/* compare counts */
2716*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp1, list1, ice_vsig_prof, list) {
2717*71d10453SEric Joyner 		count++;
2718*71d10453SEric Joyner 	}
2719*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp2, list2, ice_vsig_prof, list) {
2720*71d10453SEric Joyner 		chk_count++;
2721*71d10453SEric Joyner 	}
2722*71d10453SEric Joyner 	if (!count || count != chk_count)
2723*71d10453SEric Joyner 		return false;
2724*71d10453SEric Joyner 
2725*71d10453SEric Joyner 	tmp1 = LIST_FIRST_ENTRY(list1, struct ice_vsig_prof, list);
2726*71d10453SEric Joyner 	tmp2 = LIST_FIRST_ENTRY(list2, struct ice_vsig_prof, list);
2727*71d10453SEric Joyner 
2728*71d10453SEric Joyner 	/* profile cookies must compare, and in the exact same order to take
2729*71d10453SEric Joyner 	 * into account priority
2730*71d10453SEric Joyner 	 */
2731*71d10453SEric Joyner 	while (count--) {
2732*71d10453SEric Joyner 		if (tmp2->profile_cookie != tmp1->profile_cookie)
2733*71d10453SEric Joyner 			return false;
2734*71d10453SEric Joyner 
2735*71d10453SEric Joyner 		tmp1 = LIST_NEXT_ENTRY(tmp1, struct ice_vsig_prof, list);
2736*71d10453SEric Joyner 		tmp2 = LIST_NEXT_ENTRY(tmp2, struct ice_vsig_prof, list);
2737*71d10453SEric Joyner 	}
2738*71d10453SEric Joyner 
2739*71d10453SEric Joyner 	return true;
2740*71d10453SEric Joyner }
2741*71d10453SEric Joyner 
2742*71d10453SEric Joyner /* VSIG Management */
2743*71d10453SEric Joyner 
2744*71d10453SEric Joyner /**
2745*71d10453SEric Joyner  * ice_vsig_update_xlt2_sect - update one section of XLT2 table
2746*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2747*71d10453SEric Joyner  * @blk: HW block
2748*71d10453SEric Joyner  * @vsi: HW VSI number to program
2749*71d10453SEric Joyner  * @vsig: VSIG for the VSI
2750*71d10453SEric Joyner  *
2751*71d10453SEric Joyner  * This function will update the XLT2 hardware table with the input VSI
2752*71d10453SEric Joyner  * group configuration.
2753*71d10453SEric Joyner  */
2754*71d10453SEric Joyner static enum ice_status
2755*71d10453SEric Joyner ice_vsig_update_xlt2_sect(struct ice_hw *hw, enum ice_block blk, u16 vsi,
2756*71d10453SEric Joyner 			  u16 vsig)
2757*71d10453SEric Joyner {
2758*71d10453SEric Joyner 	struct ice_xlt2_section *sect;
2759*71d10453SEric Joyner 	struct ice_buf_build *bld;
2760*71d10453SEric Joyner 	enum ice_status status;
2761*71d10453SEric Joyner 
2762*71d10453SEric Joyner 	bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT2),
2763*71d10453SEric Joyner 					       sizeof(struct ice_xlt2_section),
2764*71d10453SEric Joyner 					       (void **)&sect);
2765*71d10453SEric Joyner 	if (!bld)
2766*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
2767*71d10453SEric Joyner 
2768*71d10453SEric Joyner 	sect->count = CPU_TO_LE16(1);
2769*71d10453SEric Joyner 	sect->offset = CPU_TO_LE16(vsi);
2770*71d10453SEric Joyner 	sect->value[0] = CPU_TO_LE16(vsig);
2771*71d10453SEric Joyner 
2772*71d10453SEric Joyner 	status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
2773*71d10453SEric Joyner 
2774*71d10453SEric Joyner 	ice_pkg_buf_free(hw, bld);
2775*71d10453SEric Joyner 
2776*71d10453SEric Joyner 	return status;
2777*71d10453SEric Joyner }
2778*71d10453SEric Joyner 
2779*71d10453SEric Joyner /**
2780*71d10453SEric Joyner  * ice_vsig_update_xlt2 - update XLT2 table with VSIG configuration
2781*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2782*71d10453SEric Joyner  * @blk: HW block
2783*71d10453SEric Joyner  *
2784*71d10453SEric Joyner  * This function will update the XLT2 hardware table with the input VSI
2785*71d10453SEric Joyner  * group configuration of used vsis.
2786*71d10453SEric Joyner  */
2787*71d10453SEric Joyner enum ice_status ice_vsig_update_xlt2(struct ice_hw *hw, enum ice_block blk)
2788*71d10453SEric Joyner {
2789*71d10453SEric Joyner 	u16 vsi;
2790*71d10453SEric Joyner 
2791*71d10453SEric Joyner 	for (vsi = 0; vsi < ICE_MAX_VSI; vsi++) {
2792*71d10453SEric Joyner 		/* update only vsis that have been changed */
2793*71d10453SEric Joyner 		if (hw->blk[blk].xlt2.vsis[vsi].changed) {
2794*71d10453SEric Joyner 			enum ice_status status;
2795*71d10453SEric Joyner 			u16 vsig;
2796*71d10453SEric Joyner 
2797*71d10453SEric Joyner 			vsig = hw->blk[blk].xlt2.vsis[vsi].vsig;
2798*71d10453SEric Joyner 			status = ice_vsig_update_xlt2_sect(hw, blk, vsi, vsig);
2799*71d10453SEric Joyner 			if (status)
2800*71d10453SEric Joyner 				return status;
2801*71d10453SEric Joyner 
2802*71d10453SEric Joyner 			hw->blk[blk].xlt2.vsis[vsi].changed = 0;
2803*71d10453SEric Joyner 		}
2804*71d10453SEric Joyner 	}
2805*71d10453SEric Joyner 
2806*71d10453SEric Joyner 	return ICE_SUCCESS;
2807*71d10453SEric Joyner }
2808*71d10453SEric Joyner 
2809*71d10453SEric Joyner /**
2810*71d10453SEric Joyner  * ice_vsig_find_vsi - find a VSIG that contains a specified VSI
2811*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2812*71d10453SEric Joyner  * @blk: HW block
2813*71d10453SEric Joyner  * @vsi: VSI of interest
2814*71d10453SEric Joyner  * @vsig: pointer to receive the VSI group
2815*71d10453SEric Joyner  *
2816*71d10453SEric Joyner  * This function will lookup the VSI entry in the XLT2 list and return
2817*71d10453SEric Joyner  * the VSI group its associated with.
2818*71d10453SEric Joyner  */
2819*71d10453SEric Joyner enum ice_status
2820*71d10453SEric Joyner ice_vsig_find_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 *vsig)
2821*71d10453SEric Joyner {
2822*71d10453SEric Joyner 	if (!vsig || vsi >= ICE_MAX_VSI)
2823*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2824*71d10453SEric Joyner 
2825*71d10453SEric Joyner 	/* As long as there's a default or valid VSIG associated with the input
2826*71d10453SEric Joyner 	 * VSI, the functions returns a success. Any handling of VSIG will be
2827*71d10453SEric Joyner 	 * done by the following add, update or remove functions.
2828*71d10453SEric Joyner 	 */
2829*71d10453SEric Joyner 	*vsig = hw->blk[blk].xlt2.vsis[vsi].vsig;
2830*71d10453SEric Joyner 
2831*71d10453SEric Joyner 	return ICE_SUCCESS;
2832*71d10453SEric Joyner }
2833*71d10453SEric Joyner 
2834*71d10453SEric Joyner /**
2835*71d10453SEric Joyner  * ice_vsig_alloc_val - allocate a new VSIG by value
2836*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2837*71d10453SEric Joyner  * @blk: HW block
2838*71d10453SEric Joyner  * @vsig: the VSIG to allocate
2839*71d10453SEric Joyner  *
2840*71d10453SEric Joyner  * This function will allocate a given VSIG specified by the VSIG parameter.
2841*71d10453SEric Joyner  */
2842*71d10453SEric Joyner static u16 ice_vsig_alloc_val(struct ice_hw *hw, enum ice_block blk, u16 vsig)
2843*71d10453SEric Joyner {
2844*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
2845*71d10453SEric Joyner 
2846*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use) {
2847*71d10453SEric Joyner 		INIT_LIST_HEAD(&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst);
2848*71d10453SEric Joyner 		hw->blk[blk].xlt2.vsig_tbl[idx].in_use = true;
2849*71d10453SEric Joyner 	}
2850*71d10453SEric Joyner 
2851*71d10453SEric Joyner 	return ICE_VSIG_VALUE(idx, hw->pf_id);
2852*71d10453SEric Joyner }
2853*71d10453SEric Joyner 
2854*71d10453SEric Joyner /**
2855*71d10453SEric Joyner  * ice_vsig_alloc - Finds a free entry and allocates a new VSIG
2856*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2857*71d10453SEric Joyner  * @blk: HW block
2858*71d10453SEric Joyner  *
2859*71d10453SEric Joyner  * This function will iterate through the VSIG list and mark the first
2860*71d10453SEric Joyner  * unused entry for the new VSIG entry as used and return that value.
2861*71d10453SEric Joyner  */
2862*71d10453SEric Joyner static u16 ice_vsig_alloc(struct ice_hw *hw, enum ice_block blk)
2863*71d10453SEric Joyner {
2864*71d10453SEric Joyner 	u16 i;
2865*71d10453SEric Joyner 
2866*71d10453SEric Joyner 	for (i = 1; i < ICE_MAX_VSIGS; i++)
2867*71d10453SEric Joyner 		if (!hw->blk[blk].xlt2.vsig_tbl[i].in_use)
2868*71d10453SEric Joyner 			return ice_vsig_alloc_val(hw, blk, i);
2869*71d10453SEric Joyner 
2870*71d10453SEric Joyner 	return ICE_DEFAULT_VSIG;
2871*71d10453SEric Joyner }
2872*71d10453SEric Joyner 
2873*71d10453SEric Joyner /**
2874*71d10453SEric Joyner  * ice_find_dup_props_vsig - find VSI group with a specified set of properties
2875*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2876*71d10453SEric Joyner  * @blk: HW block
2877*71d10453SEric Joyner  * @chs: characteristic list
2878*71d10453SEric Joyner  * @vsig: returns the VSIG with the matching profiles, if found
2879*71d10453SEric Joyner  *
2880*71d10453SEric Joyner  * Each VSIG is associated with a characteristic set; i.e. all VSIs under
2881*71d10453SEric Joyner  * a group have the same characteristic set. To check if there exists a VSIG
2882*71d10453SEric Joyner  * which has the same characteristics as the input characteristics; this
2883*71d10453SEric Joyner  * function will iterate through the XLT2 list and return the VSIG that has a
2884*71d10453SEric Joyner  * matching configuration. In order to make sure that priorities are accounted
2885*71d10453SEric Joyner  * for, the list must match exactly, including the order in which the
2886*71d10453SEric Joyner  * characteristics are listed.
2887*71d10453SEric Joyner  */
2888*71d10453SEric Joyner static enum ice_status
2889*71d10453SEric Joyner ice_find_dup_props_vsig(struct ice_hw *hw, enum ice_block blk,
2890*71d10453SEric Joyner 			struct LIST_HEAD_TYPE *chs, u16 *vsig)
2891*71d10453SEric Joyner {
2892*71d10453SEric Joyner 	struct ice_xlt2 *xlt2 = &hw->blk[blk].xlt2;
2893*71d10453SEric Joyner 	u16 i;
2894*71d10453SEric Joyner 
2895*71d10453SEric Joyner 	for (i = 0; i < xlt2->count; i++) {
2896*71d10453SEric Joyner 		if (xlt2->vsig_tbl[i].in_use &&
2897*71d10453SEric Joyner 		    ice_match_prop_lst(chs, &xlt2->vsig_tbl[i].prop_lst)) {
2898*71d10453SEric Joyner 			*vsig = ICE_VSIG_VALUE(i, hw->pf_id);
2899*71d10453SEric Joyner 			return ICE_SUCCESS;
2900*71d10453SEric Joyner 		}
2901*71d10453SEric Joyner 	}
2902*71d10453SEric Joyner 
2903*71d10453SEric Joyner 	return ICE_ERR_DOES_NOT_EXIST;
2904*71d10453SEric Joyner }
2905*71d10453SEric Joyner 
2906*71d10453SEric Joyner /**
2907*71d10453SEric Joyner  * ice_vsig_free - free VSI group
2908*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2909*71d10453SEric Joyner  * @blk: HW block
2910*71d10453SEric Joyner  * @vsig: VSIG to remove
2911*71d10453SEric Joyner  *
2912*71d10453SEric Joyner  * The function will remove all VSIs associated with the input VSIG and move
2913*71d10453SEric Joyner  * them to the DEFAULT_VSIG and mark the VSIG available.
2914*71d10453SEric Joyner  */
2915*71d10453SEric Joyner static enum ice_status
2916*71d10453SEric Joyner ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig)
2917*71d10453SEric Joyner {
2918*71d10453SEric Joyner 	struct ice_vsig_prof *dtmp, *del;
2919*71d10453SEric Joyner 	struct ice_vsig_vsi *vsi_cur;
2920*71d10453SEric Joyner 	u16 idx;
2921*71d10453SEric Joyner 
2922*71d10453SEric Joyner 	idx = vsig & ICE_VSIG_IDX_M;
2923*71d10453SEric Joyner 	if (idx >= ICE_MAX_VSIGS)
2924*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2925*71d10453SEric Joyner 
2926*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
2927*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
2928*71d10453SEric Joyner 
2929*71d10453SEric Joyner 	hw->blk[blk].xlt2.vsig_tbl[idx].in_use = false;
2930*71d10453SEric Joyner 
2931*71d10453SEric Joyner 	vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
2932*71d10453SEric Joyner 	/* If the VSIG has at least 1 VSI then iterate through the
2933*71d10453SEric Joyner 	 * list and remove the VSIs before deleting the group.
2934*71d10453SEric Joyner 	 */
2935*71d10453SEric Joyner 	if (vsi_cur) {
2936*71d10453SEric Joyner 		/* remove all vsis associated with this VSIG XLT2 entry */
2937*71d10453SEric Joyner 		do {
2938*71d10453SEric Joyner 			struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
2939*71d10453SEric Joyner 
2940*71d10453SEric Joyner 			vsi_cur->vsig = ICE_DEFAULT_VSIG;
2941*71d10453SEric Joyner 			vsi_cur->changed = 1;
2942*71d10453SEric Joyner 			vsi_cur->next_vsi = NULL;
2943*71d10453SEric Joyner 			vsi_cur = tmp;
2944*71d10453SEric Joyner 		} while (vsi_cur);
2945*71d10453SEric Joyner 
2946*71d10453SEric Joyner 		/* NULL terminate head of VSI list */
2947*71d10453SEric Joyner 		hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = NULL;
2948*71d10453SEric Joyner 	}
2949*71d10453SEric Joyner 
2950*71d10453SEric Joyner 	/* free characteristic list */
2951*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, dtmp,
2952*71d10453SEric Joyner 				 &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
2953*71d10453SEric Joyner 				 ice_vsig_prof, list) {
2954*71d10453SEric Joyner 		LIST_DEL(&del->list);
2955*71d10453SEric Joyner 		ice_free(hw, del);
2956*71d10453SEric Joyner 	}
2957*71d10453SEric Joyner 
2958*71d10453SEric Joyner 	/* if VSIG characteristic list was cleared for reset
2959*71d10453SEric Joyner 	 * re-initialize the list head
2960*71d10453SEric Joyner 	 */
2961*71d10453SEric Joyner 	INIT_LIST_HEAD(&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst);
2962*71d10453SEric Joyner 
2963*71d10453SEric Joyner 	return ICE_SUCCESS;
2964*71d10453SEric Joyner }
2965*71d10453SEric Joyner 
2966*71d10453SEric Joyner /**
2967*71d10453SEric Joyner  * ice_vsig_remove_vsi - remove VSI from VSIG
2968*71d10453SEric Joyner  * @hw: pointer to the hardware structure
2969*71d10453SEric Joyner  * @blk: HW block
2970*71d10453SEric Joyner  * @vsi: VSI to remove
2971*71d10453SEric Joyner  * @vsig: VSI group to remove from
2972*71d10453SEric Joyner  *
2973*71d10453SEric Joyner  * The function will remove the input VSI from its VSI group and move it
2974*71d10453SEric Joyner  * to the DEFAULT_VSIG.
2975*71d10453SEric Joyner  */
2976*71d10453SEric Joyner static enum ice_status
2977*71d10453SEric Joyner ice_vsig_remove_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
2978*71d10453SEric Joyner {
2979*71d10453SEric Joyner 	struct ice_vsig_vsi **vsi_head, *vsi_cur, *vsi_tgt;
2980*71d10453SEric Joyner 	u16 idx;
2981*71d10453SEric Joyner 
2982*71d10453SEric Joyner 	idx = vsig & ICE_VSIG_IDX_M;
2983*71d10453SEric Joyner 
2984*71d10453SEric Joyner 	if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS)
2985*71d10453SEric Joyner 		return ICE_ERR_PARAM;
2986*71d10453SEric Joyner 
2987*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
2988*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
2989*71d10453SEric Joyner 
2990*71d10453SEric Joyner 	/* entry already in default VSIG, don't have to remove */
2991*71d10453SEric Joyner 	if (idx == ICE_DEFAULT_VSIG)
2992*71d10453SEric Joyner 		return ICE_SUCCESS;
2993*71d10453SEric Joyner 
2994*71d10453SEric Joyner 	vsi_head = &hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
2995*71d10453SEric Joyner 	if (!(*vsi_head))
2996*71d10453SEric Joyner 		return ICE_ERR_CFG;
2997*71d10453SEric Joyner 
2998*71d10453SEric Joyner 	vsi_tgt = &hw->blk[blk].xlt2.vsis[vsi];
2999*71d10453SEric Joyner 	vsi_cur = (*vsi_head);
3000*71d10453SEric Joyner 
3001*71d10453SEric Joyner 	/* iterate the VSI list, skip over the entry to be removed */
3002*71d10453SEric Joyner 	while (vsi_cur) {
3003*71d10453SEric Joyner 		if (vsi_tgt == vsi_cur) {
3004*71d10453SEric Joyner 			(*vsi_head) = vsi_cur->next_vsi;
3005*71d10453SEric Joyner 			break;
3006*71d10453SEric Joyner 		}
3007*71d10453SEric Joyner 		vsi_head = &vsi_cur->next_vsi;
3008*71d10453SEric Joyner 		vsi_cur = vsi_cur->next_vsi;
3009*71d10453SEric Joyner 	}
3010*71d10453SEric Joyner 
3011*71d10453SEric Joyner 	/* verify if VSI was removed from group list */
3012*71d10453SEric Joyner 	if (!vsi_cur)
3013*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
3014*71d10453SEric Joyner 
3015*71d10453SEric Joyner 	vsi_cur->vsig = ICE_DEFAULT_VSIG;
3016*71d10453SEric Joyner 	vsi_cur->changed = 1;
3017*71d10453SEric Joyner 	vsi_cur->next_vsi = NULL;
3018*71d10453SEric Joyner 
3019*71d10453SEric Joyner 	return ICE_SUCCESS;
3020*71d10453SEric Joyner }
3021*71d10453SEric Joyner 
3022*71d10453SEric Joyner /**
3023*71d10453SEric Joyner  * ice_vsig_add_mv_vsi - add or move a VSI to a VSI group
3024*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3025*71d10453SEric Joyner  * @blk: HW block
3026*71d10453SEric Joyner  * @vsi: VSI to move
3027*71d10453SEric Joyner  * @vsig: destination VSI group
3028*71d10453SEric Joyner  *
3029*71d10453SEric Joyner  * This function will move or add the input VSI to the target VSIG.
3030*71d10453SEric Joyner  * The function will find the original VSIG the VSI belongs to and
3031*71d10453SEric Joyner  * move the entry to the DEFAULT_VSIG, update the original VSIG and
3032*71d10453SEric Joyner  * then move entry to the new VSIG.
3033*71d10453SEric Joyner  */
3034*71d10453SEric Joyner static enum ice_status
3035*71d10453SEric Joyner ice_vsig_add_mv_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
3036*71d10453SEric Joyner {
3037*71d10453SEric Joyner 	struct ice_vsig_vsi *tmp;
3038*71d10453SEric Joyner 	enum ice_status status;
3039*71d10453SEric Joyner 	u16 orig_vsig, idx;
3040*71d10453SEric Joyner 
3041*71d10453SEric Joyner 	idx = vsig & ICE_VSIG_IDX_M;
3042*71d10453SEric Joyner 
3043*71d10453SEric Joyner 	if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS)
3044*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3045*71d10453SEric Joyner 
3046*71d10453SEric Joyner 	/* if VSIG not in use and VSIG is not default type this VSIG
3047*71d10453SEric Joyner 	 * doesn't exist.
3048*71d10453SEric Joyner 	 */
3049*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use &&
3050*71d10453SEric Joyner 	    vsig != ICE_DEFAULT_VSIG)
3051*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
3052*71d10453SEric Joyner 
3053*71d10453SEric Joyner 	status = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig);
3054*71d10453SEric Joyner 	if (status)
3055*71d10453SEric Joyner 		return status;
3056*71d10453SEric Joyner 
3057*71d10453SEric Joyner 	/* no update required if vsigs match */
3058*71d10453SEric Joyner 	if (orig_vsig == vsig)
3059*71d10453SEric Joyner 		return ICE_SUCCESS;
3060*71d10453SEric Joyner 
3061*71d10453SEric Joyner 	if (orig_vsig != ICE_DEFAULT_VSIG) {
3062*71d10453SEric Joyner 		/* remove entry from orig_vsig and add to default VSIG */
3063*71d10453SEric Joyner 		status = ice_vsig_remove_vsi(hw, blk, vsi, orig_vsig);
3064*71d10453SEric Joyner 		if (status)
3065*71d10453SEric Joyner 			return status;
3066*71d10453SEric Joyner 	}
3067*71d10453SEric Joyner 
3068*71d10453SEric Joyner 	if (idx == ICE_DEFAULT_VSIG)
3069*71d10453SEric Joyner 		return ICE_SUCCESS;
3070*71d10453SEric Joyner 
3071*71d10453SEric Joyner 	/* Create VSI entry and add VSIG and prop_mask values */
3072*71d10453SEric Joyner 	hw->blk[blk].xlt2.vsis[vsi].vsig = vsig;
3073*71d10453SEric Joyner 	hw->blk[blk].xlt2.vsis[vsi].changed = 1;
3074*71d10453SEric Joyner 
3075*71d10453SEric Joyner 	/* Add new entry to the head of the VSIG list */
3076*71d10453SEric Joyner 	tmp = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
3077*71d10453SEric Joyner 	hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi =
3078*71d10453SEric Joyner 		&hw->blk[blk].xlt2.vsis[vsi];
3079*71d10453SEric Joyner 	hw->blk[blk].xlt2.vsis[vsi].next_vsi = tmp;
3080*71d10453SEric Joyner 	hw->blk[blk].xlt2.t[vsi] = vsig;
3081*71d10453SEric Joyner 
3082*71d10453SEric Joyner 	return ICE_SUCCESS;
3083*71d10453SEric Joyner }
3084*71d10453SEric Joyner 
3085*71d10453SEric Joyner /**
3086*71d10453SEric Joyner  * ice_find_prof_id - find profile ID for a given field vector
3087*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3088*71d10453SEric Joyner  * @blk: HW block
3089*71d10453SEric Joyner  * @fv: field vector to search for
3090*71d10453SEric Joyner  * @prof_id: receives the profile ID
3091*71d10453SEric Joyner  */
3092*71d10453SEric Joyner static enum ice_status
3093*71d10453SEric Joyner ice_find_prof_id(struct ice_hw *hw, enum ice_block blk,
3094*71d10453SEric Joyner 		 struct ice_fv_word *fv, u8 *prof_id)
3095*71d10453SEric Joyner {
3096*71d10453SEric Joyner 	struct ice_es *es = &hw->blk[blk].es;
3097*71d10453SEric Joyner 	u16 off;
3098*71d10453SEric Joyner 	u8 i;
3099*71d10453SEric Joyner 
3100*71d10453SEric Joyner 	for (i = 0; i < (u8)es->count; i++) {
3101*71d10453SEric Joyner 		off = i * es->fvw;
3102*71d10453SEric Joyner 
3103*71d10453SEric Joyner 		if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
3104*71d10453SEric Joyner 			continue;
3105*71d10453SEric Joyner 
3106*71d10453SEric Joyner 		*prof_id = i;
3107*71d10453SEric Joyner 		return ICE_SUCCESS;
3108*71d10453SEric Joyner 	}
3109*71d10453SEric Joyner 
3110*71d10453SEric Joyner 	return ICE_ERR_DOES_NOT_EXIST;
3111*71d10453SEric Joyner }
3112*71d10453SEric Joyner 
3113*71d10453SEric Joyner /**
3114*71d10453SEric Joyner  * ice_prof_id_rsrc_type - get profile ID resource type for a block type
3115*71d10453SEric Joyner  * @blk: the block type
3116*71d10453SEric Joyner  * @rsrc_type: pointer to variable to receive the resource type
3117*71d10453SEric Joyner  */
3118*71d10453SEric Joyner static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type)
3119*71d10453SEric Joyner {
3120*71d10453SEric Joyner 	switch (blk) {
3121*71d10453SEric Joyner 	case ICE_BLK_SW:
3122*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_SWITCH_PROF_BLDR_PROFID;
3123*71d10453SEric Joyner 		break;
3124*71d10453SEric Joyner 	case ICE_BLK_ACL:
3125*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_ACL_PROF_BLDR_PROFID;
3126*71d10453SEric Joyner 		break;
3127*71d10453SEric Joyner 	case ICE_BLK_FD:
3128*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_PROFID;
3129*71d10453SEric Joyner 		break;
3130*71d10453SEric Joyner 	case ICE_BLK_RSS:
3131*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID;
3132*71d10453SEric Joyner 		break;
3133*71d10453SEric Joyner 	case ICE_BLK_PE:
3134*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_PROFID;
3135*71d10453SEric Joyner 		break;
3136*71d10453SEric Joyner 	default:
3137*71d10453SEric Joyner 		return false;
3138*71d10453SEric Joyner 	}
3139*71d10453SEric Joyner 	return true;
3140*71d10453SEric Joyner }
3141*71d10453SEric Joyner 
3142*71d10453SEric Joyner /**
3143*71d10453SEric Joyner  * ice_tcam_ent_rsrc_type - get TCAM entry resource type for a block type
3144*71d10453SEric Joyner  * @blk: the block type
3145*71d10453SEric Joyner  * @rsrc_type: pointer to variable to receive the resource type
3146*71d10453SEric Joyner  */
3147*71d10453SEric Joyner static bool ice_tcam_ent_rsrc_type(enum ice_block blk, u16 *rsrc_type)
3148*71d10453SEric Joyner {
3149*71d10453SEric Joyner 	switch (blk) {
3150*71d10453SEric Joyner 	case ICE_BLK_SW:
3151*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_SWITCH_PROF_BLDR_TCAM;
3152*71d10453SEric Joyner 		break;
3153*71d10453SEric Joyner 	case ICE_BLK_ACL:
3154*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_ACL_PROF_BLDR_TCAM;
3155*71d10453SEric Joyner 		break;
3156*71d10453SEric Joyner 	case ICE_BLK_FD:
3157*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_TCAM;
3158*71d10453SEric Joyner 		break;
3159*71d10453SEric Joyner 	case ICE_BLK_RSS:
3160*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM;
3161*71d10453SEric Joyner 		break;
3162*71d10453SEric Joyner 	case ICE_BLK_PE:
3163*71d10453SEric Joyner 		*rsrc_type = ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_TCAM;
3164*71d10453SEric Joyner 		break;
3165*71d10453SEric Joyner 	default:
3166*71d10453SEric Joyner 		return false;
3167*71d10453SEric Joyner 	}
3168*71d10453SEric Joyner 	return true;
3169*71d10453SEric Joyner }
3170*71d10453SEric Joyner 
3171*71d10453SEric Joyner /**
3172*71d10453SEric Joyner  * ice_alloc_tcam_ent - allocate hardware TCAM entry
3173*71d10453SEric Joyner  * @hw: pointer to the HW struct
3174*71d10453SEric Joyner  * @blk: the block to allocate the TCAM for
3175*71d10453SEric Joyner  * @tcam_idx: pointer to variable to receive the TCAM entry
3176*71d10453SEric Joyner  *
3177*71d10453SEric Joyner  * This function allocates a new entry in a Profile ID TCAM for a specific
3178*71d10453SEric Joyner  * block.
3179*71d10453SEric Joyner  */
3180*71d10453SEric Joyner static enum ice_status
3181*71d10453SEric Joyner ice_alloc_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 *tcam_idx)
3182*71d10453SEric Joyner {
3183*71d10453SEric Joyner 	u16 res_type;
3184*71d10453SEric Joyner 
3185*71d10453SEric Joyner 	if (!ice_tcam_ent_rsrc_type(blk, &res_type))
3186*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3187*71d10453SEric Joyner 
3188*71d10453SEric Joyner 	return ice_alloc_hw_res(hw, res_type, 1, true, tcam_idx);
3189*71d10453SEric Joyner }
3190*71d10453SEric Joyner 
3191*71d10453SEric Joyner /**
3192*71d10453SEric Joyner  * ice_free_tcam_ent - free hardware TCAM entry
3193*71d10453SEric Joyner  * @hw: pointer to the HW struct
3194*71d10453SEric Joyner  * @blk: the block from which to free the TCAM entry
3195*71d10453SEric Joyner  * @tcam_idx: the TCAM entry to free
3196*71d10453SEric Joyner  *
3197*71d10453SEric Joyner  * This function frees an entry in a Profile ID TCAM for a specific block.
3198*71d10453SEric Joyner  */
3199*71d10453SEric Joyner static enum ice_status
3200*71d10453SEric Joyner ice_free_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 tcam_idx)
3201*71d10453SEric Joyner {
3202*71d10453SEric Joyner 	u16 res_type;
3203*71d10453SEric Joyner 
3204*71d10453SEric Joyner 	if (!ice_tcam_ent_rsrc_type(blk, &res_type))
3205*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3206*71d10453SEric Joyner 
3207*71d10453SEric Joyner 	return ice_free_hw_res(hw, res_type, 1, &tcam_idx);
3208*71d10453SEric Joyner }
3209*71d10453SEric Joyner 
3210*71d10453SEric Joyner /**
3211*71d10453SEric Joyner  * ice_alloc_prof_id - allocate profile ID
3212*71d10453SEric Joyner  * @hw: pointer to the HW struct
3213*71d10453SEric Joyner  * @blk: the block to allocate the profile ID for
3214*71d10453SEric Joyner  * @prof_id: pointer to variable to receive the profile ID
3215*71d10453SEric Joyner  *
3216*71d10453SEric Joyner  * This function allocates a new profile ID, which also corresponds to a Field
3217*71d10453SEric Joyner  * Vector (Extraction Sequence) entry.
3218*71d10453SEric Joyner  */
3219*71d10453SEric Joyner static enum ice_status
3220*71d10453SEric Joyner ice_alloc_prof_id(struct ice_hw *hw, enum ice_block blk, u8 *prof_id)
3221*71d10453SEric Joyner {
3222*71d10453SEric Joyner 	enum ice_status status;
3223*71d10453SEric Joyner 	u16 res_type;
3224*71d10453SEric Joyner 	u16 get_prof;
3225*71d10453SEric Joyner 
3226*71d10453SEric Joyner 	if (!ice_prof_id_rsrc_type(blk, &res_type))
3227*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3228*71d10453SEric Joyner 
3229*71d10453SEric Joyner 	status = ice_alloc_hw_res(hw, res_type, 1, false, &get_prof);
3230*71d10453SEric Joyner 	if (!status)
3231*71d10453SEric Joyner 		*prof_id = (u8)get_prof;
3232*71d10453SEric Joyner 
3233*71d10453SEric Joyner 	return status;
3234*71d10453SEric Joyner }
3235*71d10453SEric Joyner 
3236*71d10453SEric Joyner /**
3237*71d10453SEric Joyner  * ice_free_prof_id - free profile ID
3238*71d10453SEric Joyner  * @hw: pointer to the HW struct
3239*71d10453SEric Joyner  * @blk: the block from which to free the profile ID
3240*71d10453SEric Joyner  * @prof_id: the profile ID to free
3241*71d10453SEric Joyner  *
3242*71d10453SEric Joyner  * This function frees a profile ID, which also corresponds to a Field Vector.
3243*71d10453SEric Joyner  */
3244*71d10453SEric Joyner static enum ice_status
3245*71d10453SEric Joyner ice_free_prof_id(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
3246*71d10453SEric Joyner {
3247*71d10453SEric Joyner 	u16 tmp_prof_id = (u16)prof_id;
3248*71d10453SEric Joyner 	u16 res_type;
3249*71d10453SEric Joyner 
3250*71d10453SEric Joyner 	if (!ice_prof_id_rsrc_type(blk, &res_type))
3251*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3252*71d10453SEric Joyner 
3253*71d10453SEric Joyner 	return ice_free_hw_res(hw, res_type, 1, &tmp_prof_id);
3254*71d10453SEric Joyner }
3255*71d10453SEric Joyner 
3256*71d10453SEric Joyner /**
3257*71d10453SEric Joyner  * ice_prof_inc_ref - increment reference count for profile
3258*71d10453SEric Joyner  * @hw: pointer to the HW struct
3259*71d10453SEric Joyner  * @blk: the block from which to free the profile ID
3260*71d10453SEric Joyner  * @prof_id: the profile ID for which to increment the reference count
3261*71d10453SEric Joyner  */
3262*71d10453SEric Joyner static enum ice_status
3263*71d10453SEric Joyner ice_prof_inc_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
3264*71d10453SEric Joyner {
3265*71d10453SEric Joyner 	if (prof_id > hw->blk[blk].es.count)
3266*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3267*71d10453SEric Joyner 
3268*71d10453SEric Joyner 	hw->blk[blk].es.ref_count[prof_id]++;
3269*71d10453SEric Joyner 
3270*71d10453SEric Joyner 	return ICE_SUCCESS;
3271*71d10453SEric Joyner }
3272*71d10453SEric Joyner 
3273*71d10453SEric Joyner /**
3274*71d10453SEric Joyner  * ice_write_es - write an extraction sequence to hardware
3275*71d10453SEric Joyner  * @hw: pointer to the HW struct
3276*71d10453SEric Joyner  * @blk: the block in which to write the extraction sequence
3277*71d10453SEric Joyner  * @prof_id: the profile ID to write
3278*71d10453SEric Joyner  * @fv: pointer to the extraction sequence to write - NULL to clear extraction
3279*71d10453SEric Joyner  */
3280*71d10453SEric Joyner static void
3281*71d10453SEric Joyner ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
3282*71d10453SEric Joyner 	     struct ice_fv_word *fv)
3283*71d10453SEric Joyner {
3284*71d10453SEric Joyner 	u16 off;
3285*71d10453SEric Joyner 
3286*71d10453SEric Joyner 	off = prof_id * hw->blk[blk].es.fvw;
3287*71d10453SEric Joyner 	if (!fv) {
3288*71d10453SEric Joyner 		ice_memset(&hw->blk[blk].es.t[off], 0, hw->blk[blk].es.fvw *
3289*71d10453SEric Joyner 			   sizeof(*fv), ICE_NONDMA_MEM);
3290*71d10453SEric Joyner 		hw->blk[blk].es.written[prof_id] = false;
3291*71d10453SEric Joyner 	} else {
3292*71d10453SEric Joyner 		ice_memcpy(&hw->blk[blk].es.t[off], fv, hw->blk[blk].es.fvw *
3293*71d10453SEric Joyner 			   sizeof(*fv), ICE_NONDMA_TO_NONDMA);
3294*71d10453SEric Joyner 	}
3295*71d10453SEric Joyner }
3296*71d10453SEric Joyner 
3297*71d10453SEric Joyner /**
3298*71d10453SEric Joyner  * ice_prof_dec_ref - decrement reference count for profile
3299*71d10453SEric Joyner  * @hw: pointer to the HW struct
3300*71d10453SEric Joyner  * @blk: the block from which to free the profile ID
3301*71d10453SEric Joyner  * @prof_id: the profile ID for which to decrement the reference count
3302*71d10453SEric Joyner  */
3303*71d10453SEric Joyner static enum ice_status
3304*71d10453SEric Joyner ice_prof_dec_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
3305*71d10453SEric Joyner {
3306*71d10453SEric Joyner 	if (prof_id > hw->blk[blk].es.count)
3307*71d10453SEric Joyner 		return ICE_ERR_PARAM;
3308*71d10453SEric Joyner 
3309*71d10453SEric Joyner 	if (hw->blk[blk].es.ref_count[prof_id] > 0) {
3310*71d10453SEric Joyner 		if (!--hw->blk[blk].es.ref_count[prof_id]) {
3311*71d10453SEric Joyner 			ice_write_es(hw, blk, prof_id, NULL);
3312*71d10453SEric Joyner 			return ice_free_prof_id(hw, blk, prof_id);
3313*71d10453SEric Joyner 		}
3314*71d10453SEric Joyner 	}
3315*71d10453SEric Joyner 
3316*71d10453SEric Joyner 	return ICE_SUCCESS;
3317*71d10453SEric Joyner }
3318*71d10453SEric Joyner 
3319*71d10453SEric Joyner /* Block / table section IDs */
3320*71d10453SEric Joyner static const u32 ice_blk_sids[ICE_BLK_COUNT][ICE_SID_OFF_COUNT] = {
3321*71d10453SEric Joyner 	/* SWITCH */
3322*71d10453SEric Joyner 	{	ICE_SID_XLT1_SW,
3323*71d10453SEric Joyner 		ICE_SID_XLT2_SW,
3324*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_SW,
3325*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_SW,
3326*71d10453SEric Joyner 		ICE_SID_FLD_VEC_SW
3327*71d10453SEric Joyner 	},
3328*71d10453SEric Joyner 
3329*71d10453SEric Joyner 	/* ACL */
3330*71d10453SEric Joyner 	{	ICE_SID_XLT1_ACL,
3331*71d10453SEric Joyner 		ICE_SID_XLT2_ACL,
3332*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_ACL,
3333*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_ACL,
3334*71d10453SEric Joyner 		ICE_SID_FLD_VEC_ACL
3335*71d10453SEric Joyner 	},
3336*71d10453SEric Joyner 
3337*71d10453SEric Joyner 	/* FD */
3338*71d10453SEric Joyner 	{	ICE_SID_XLT1_FD,
3339*71d10453SEric Joyner 		ICE_SID_XLT2_FD,
3340*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_FD,
3341*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_FD,
3342*71d10453SEric Joyner 		ICE_SID_FLD_VEC_FD
3343*71d10453SEric Joyner 	},
3344*71d10453SEric Joyner 
3345*71d10453SEric Joyner 	/* RSS */
3346*71d10453SEric Joyner 	{	ICE_SID_XLT1_RSS,
3347*71d10453SEric Joyner 		ICE_SID_XLT2_RSS,
3348*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_RSS,
3349*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_RSS,
3350*71d10453SEric Joyner 		ICE_SID_FLD_VEC_RSS
3351*71d10453SEric Joyner 	},
3352*71d10453SEric Joyner 
3353*71d10453SEric Joyner 	/* PE */
3354*71d10453SEric Joyner 	{	ICE_SID_XLT1_PE,
3355*71d10453SEric Joyner 		ICE_SID_XLT2_PE,
3356*71d10453SEric Joyner 		ICE_SID_PROFID_TCAM_PE,
3357*71d10453SEric Joyner 		ICE_SID_PROFID_REDIR_PE,
3358*71d10453SEric Joyner 		ICE_SID_FLD_VEC_PE
3359*71d10453SEric Joyner 	}
3360*71d10453SEric Joyner };
3361*71d10453SEric Joyner 
3362*71d10453SEric Joyner /**
3363*71d10453SEric Joyner  * ice_init_sw_xlt1_db - init software XLT1 database from HW tables
3364*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3365*71d10453SEric Joyner  * @blk: the HW block to initialize
3366*71d10453SEric Joyner  */
3367*71d10453SEric Joyner static void ice_init_sw_xlt1_db(struct ice_hw *hw, enum ice_block blk)
3368*71d10453SEric Joyner {
3369*71d10453SEric Joyner 	u16 pt;
3370*71d10453SEric Joyner 
3371*71d10453SEric Joyner 	for (pt = 0; pt < hw->blk[blk].xlt1.count; pt++) {
3372*71d10453SEric Joyner 		u8 ptg;
3373*71d10453SEric Joyner 
3374*71d10453SEric Joyner 		ptg = hw->blk[blk].xlt1.t[pt];
3375*71d10453SEric Joyner 		if (ptg != ICE_DEFAULT_PTG) {
3376*71d10453SEric Joyner 			ice_ptg_alloc_val(hw, blk, ptg);
3377*71d10453SEric Joyner 			ice_ptg_add_mv_ptype(hw, blk, pt, ptg);
3378*71d10453SEric Joyner 		}
3379*71d10453SEric Joyner 	}
3380*71d10453SEric Joyner }
3381*71d10453SEric Joyner 
3382*71d10453SEric Joyner /**
3383*71d10453SEric Joyner  * ice_init_sw_xlt2_db - init software XLT2 database from HW tables
3384*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3385*71d10453SEric Joyner  * @blk: the HW block to initialize
3386*71d10453SEric Joyner  */
3387*71d10453SEric Joyner static void ice_init_sw_xlt2_db(struct ice_hw *hw, enum ice_block blk)
3388*71d10453SEric Joyner {
3389*71d10453SEric Joyner 	u16 vsi;
3390*71d10453SEric Joyner 
3391*71d10453SEric Joyner 	for (vsi = 0; vsi < hw->blk[blk].xlt2.count; vsi++) {
3392*71d10453SEric Joyner 		u16 vsig;
3393*71d10453SEric Joyner 
3394*71d10453SEric Joyner 		vsig = hw->blk[blk].xlt2.t[vsi];
3395*71d10453SEric Joyner 		if (vsig) {
3396*71d10453SEric Joyner 			ice_vsig_alloc_val(hw, blk, vsig);
3397*71d10453SEric Joyner 			ice_vsig_add_mv_vsi(hw, blk, vsi, vsig);
3398*71d10453SEric Joyner 			/* no changes at this time, since this has been
3399*71d10453SEric Joyner 			 * initialized from the original package
3400*71d10453SEric Joyner 			 */
3401*71d10453SEric Joyner 			hw->blk[blk].xlt2.vsis[vsi].changed = 0;
3402*71d10453SEric Joyner 		}
3403*71d10453SEric Joyner 	}
3404*71d10453SEric Joyner }
3405*71d10453SEric Joyner 
3406*71d10453SEric Joyner /**
3407*71d10453SEric Joyner  * ice_init_sw_db - init software database from HW tables
3408*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3409*71d10453SEric Joyner  */
3410*71d10453SEric Joyner static void ice_init_sw_db(struct ice_hw *hw)
3411*71d10453SEric Joyner {
3412*71d10453SEric Joyner 	u16 i;
3413*71d10453SEric Joyner 
3414*71d10453SEric Joyner 	for (i = 0; i < ICE_BLK_COUNT; i++) {
3415*71d10453SEric Joyner 		ice_init_sw_xlt1_db(hw, (enum ice_block)i);
3416*71d10453SEric Joyner 		ice_init_sw_xlt2_db(hw, (enum ice_block)i);
3417*71d10453SEric Joyner 	}
3418*71d10453SEric Joyner }
3419*71d10453SEric Joyner 
3420*71d10453SEric Joyner /**
3421*71d10453SEric Joyner  * ice_fill_tbl - Reads content of a single table type into database
3422*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3423*71d10453SEric Joyner  * @block_id: Block ID of the table to copy
3424*71d10453SEric Joyner  * @sid: Section ID of the table to copy
3425*71d10453SEric Joyner  *
3426*71d10453SEric Joyner  * Will attempt to read the entire content of a given table of a single block
3427*71d10453SEric Joyner  * into the driver database. We assume that the buffer will always
3428*71d10453SEric Joyner  * be as large or larger than the data contained in the package. If
3429*71d10453SEric Joyner  * this condition is not met, there is most likely an error in the package
3430*71d10453SEric Joyner  * contents.
3431*71d10453SEric Joyner  */
3432*71d10453SEric Joyner static void ice_fill_tbl(struct ice_hw *hw, enum ice_block block_id, u32 sid)
3433*71d10453SEric Joyner {
3434*71d10453SEric Joyner 	u32 dst_len, sect_len, offset = 0;
3435*71d10453SEric Joyner 	struct ice_prof_redir_section *pr;
3436*71d10453SEric Joyner 	struct ice_prof_id_section *pid;
3437*71d10453SEric Joyner 	struct ice_xlt1_section *xlt1;
3438*71d10453SEric Joyner 	struct ice_xlt2_section *xlt2;
3439*71d10453SEric Joyner 	struct ice_sw_fv_section *es;
3440*71d10453SEric Joyner 	struct ice_pkg_enum state;
3441*71d10453SEric Joyner 	u8 *src, *dst;
3442*71d10453SEric Joyner 	void *sect;
3443*71d10453SEric Joyner 
3444*71d10453SEric Joyner 	/* if the HW segment pointer is null then the first iteration of
3445*71d10453SEric Joyner 	 * ice_pkg_enum_section() will fail. In this case the HW tables will
3446*71d10453SEric Joyner 	 * not be filled and return success.
3447*71d10453SEric Joyner 	 */
3448*71d10453SEric Joyner 	if (!hw->seg) {
3449*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "hw->seg is NULL, tables are not filled\n");
3450*71d10453SEric Joyner 		return;
3451*71d10453SEric Joyner 	}
3452*71d10453SEric Joyner 
3453*71d10453SEric Joyner 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
3454*71d10453SEric Joyner 
3455*71d10453SEric Joyner 	sect = ice_pkg_enum_section(hw->seg, &state, sid);
3456*71d10453SEric Joyner 
3457*71d10453SEric Joyner 	while (sect) {
3458*71d10453SEric Joyner 		switch (sid) {
3459*71d10453SEric Joyner 		case ICE_SID_XLT1_SW:
3460*71d10453SEric Joyner 		case ICE_SID_XLT1_FD:
3461*71d10453SEric Joyner 		case ICE_SID_XLT1_RSS:
3462*71d10453SEric Joyner 		case ICE_SID_XLT1_ACL:
3463*71d10453SEric Joyner 		case ICE_SID_XLT1_PE:
3464*71d10453SEric Joyner 			xlt1 = (struct ice_xlt1_section *)sect;
3465*71d10453SEric Joyner 			src = xlt1->value;
3466*71d10453SEric Joyner 			sect_len = LE16_TO_CPU(xlt1->count) *
3467*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].xlt1.t);
3468*71d10453SEric Joyner 			dst = hw->blk[block_id].xlt1.t;
3469*71d10453SEric Joyner 			dst_len = hw->blk[block_id].xlt1.count *
3470*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].xlt1.t);
3471*71d10453SEric Joyner 			break;
3472*71d10453SEric Joyner 		case ICE_SID_XLT2_SW:
3473*71d10453SEric Joyner 		case ICE_SID_XLT2_FD:
3474*71d10453SEric Joyner 		case ICE_SID_XLT2_RSS:
3475*71d10453SEric Joyner 		case ICE_SID_XLT2_ACL:
3476*71d10453SEric Joyner 		case ICE_SID_XLT2_PE:
3477*71d10453SEric Joyner 			xlt2 = (struct ice_xlt2_section *)sect;
3478*71d10453SEric Joyner 			src = (_FORCE_ u8 *)xlt2->value;
3479*71d10453SEric Joyner 			sect_len = LE16_TO_CPU(xlt2->count) *
3480*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].xlt2.t);
3481*71d10453SEric Joyner 			dst = (u8 *)hw->blk[block_id].xlt2.t;
3482*71d10453SEric Joyner 			dst_len = hw->blk[block_id].xlt2.count *
3483*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].xlt2.t);
3484*71d10453SEric Joyner 			break;
3485*71d10453SEric Joyner 		case ICE_SID_PROFID_TCAM_SW:
3486*71d10453SEric Joyner 		case ICE_SID_PROFID_TCAM_FD:
3487*71d10453SEric Joyner 		case ICE_SID_PROFID_TCAM_RSS:
3488*71d10453SEric Joyner 		case ICE_SID_PROFID_TCAM_ACL:
3489*71d10453SEric Joyner 		case ICE_SID_PROFID_TCAM_PE:
3490*71d10453SEric Joyner 			pid = (struct ice_prof_id_section *)sect;
3491*71d10453SEric Joyner 			src = (u8 *)pid->entry;
3492*71d10453SEric Joyner 			sect_len = LE16_TO_CPU(pid->count) *
3493*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].prof.t);
3494*71d10453SEric Joyner 			dst = (u8 *)hw->blk[block_id].prof.t;
3495*71d10453SEric Joyner 			dst_len = hw->blk[block_id].prof.count *
3496*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].prof.t);
3497*71d10453SEric Joyner 			break;
3498*71d10453SEric Joyner 		case ICE_SID_PROFID_REDIR_SW:
3499*71d10453SEric Joyner 		case ICE_SID_PROFID_REDIR_FD:
3500*71d10453SEric Joyner 		case ICE_SID_PROFID_REDIR_RSS:
3501*71d10453SEric Joyner 		case ICE_SID_PROFID_REDIR_ACL:
3502*71d10453SEric Joyner 		case ICE_SID_PROFID_REDIR_PE:
3503*71d10453SEric Joyner 			pr = (struct ice_prof_redir_section *)sect;
3504*71d10453SEric Joyner 			src = pr->redir_value;
3505*71d10453SEric Joyner 			sect_len = LE16_TO_CPU(pr->count) *
3506*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].prof_redir.t);
3507*71d10453SEric Joyner 			dst = hw->blk[block_id].prof_redir.t;
3508*71d10453SEric Joyner 			dst_len = hw->blk[block_id].prof_redir.count *
3509*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].prof_redir.t);
3510*71d10453SEric Joyner 			break;
3511*71d10453SEric Joyner 		case ICE_SID_FLD_VEC_SW:
3512*71d10453SEric Joyner 		case ICE_SID_FLD_VEC_FD:
3513*71d10453SEric Joyner 		case ICE_SID_FLD_VEC_RSS:
3514*71d10453SEric Joyner 		case ICE_SID_FLD_VEC_ACL:
3515*71d10453SEric Joyner 		case ICE_SID_FLD_VEC_PE:
3516*71d10453SEric Joyner 			es = (struct ice_sw_fv_section *)sect;
3517*71d10453SEric Joyner 			src = (u8 *)es->fv;
3518*71d10453SEric Joyner 			sect_len = (u32)(LE16_TO_CPU(es->count) *
3519*71d10453SEric Joyner 					 hw->blk[block_id].es.fvw) *
3520*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].es.t);
3521*71d10453SEric Joyner 			dst = (u8 *)hw->blk[block_id].es.t;
3522*71d10453SEric Joyner 			dst_len = (u32)(hw->blk[block_id].es.count *
3523*71d10453SEric Joyner 					hw->blk[block_id].es.fvw) *
3524*71d10453SEric Joyner 				sizeof(*hw->blk[block_id].es.t);
3525*71d10453SEric Joyner 			break;
3526*71d10453SEric Joyner 		default:
3527*71d10453SEric Joyner 			return;
3528*71d10453SEric Joyner 		}
3529*71d10453SEric Joyner 
3530*71d10453SEric Joyner 		/* if the section offset exceeds destination length, terminate
3531*71d10453SEric Joyner 		 * table fill.
3532*71d10453SEric Joyner 		 */
3533*71d10453SEric Joyner 		if (offset > dst_len)
3534*71d10453SEric Joyner 			return;
3535*71d10453SEric Joyner 
3536*71d10453SEric Joyner 		/* if the sum of section size and offset exceed destination size
3537*71d10453SEric Joyner 		 * then we are out of bounds of the HW table size for that PF.
3538*71d10453SEric Joyner 		 * Changing section length to fill the remaining table space
3539*71d10453SEric Joyner 		 * of that PF.
3540*71d10453SEric Joyner 		 */
3541*71d10453SEric Joyner 		if ((offset + sect_len) > dst_len)
3542*71d10453SEric Joyner 			sect_len = dst_len - offset;
3543*71d10453SEric Joyner 
3544*71d10453SEric Joyner 		ice_memcpy(dst + offset, src, sect_len, ICE_NONDMA_TO_NONDMA);
3545*71d10453SEric Joyner 		offset += sect_len;
3546*71d10453SEric Joyner 		sect = ice_pkg_enum_section(NULL, &state, sid);
3547*71d10453SEric Joyner 	}
3548*71d10453SEric Joyner }
3549*71d10453SEric Joyner 
3550*71d10453SEric Joyner /**
3551*71d10453SEric Joyner  * ice_fill_blk_tbls - Read package context for tables
3552*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3553*71d10453SEric Joyner  *
3554*71d10453SEric Joyner  * Reads the current package contents and populates the driver
3555*71d10453SEric Joyner  * database with the data iteratively for all advanced feature
3556*71d10453SEric Joyner  * blocks. Assume that the HW tables have been allocated.
3557*71d10453SEric Joyner  */
3558*71d10453SEric Joyner void ice_fill_blk_tbls(struct ice_hw *hw)
3559*71d10453SEric Joyner {
3560*71d10453SEric Joyner 	u8 i;
3561*71d10453SEric Joyner 
3562*71d10453SEric Joyner 	for (i = 0; i < ICE_BLK_COUNT; i++) {
3563*71d10453SEric Joyner 		enum ice_block blk_id = (enum ice_block)i;
3564*71d10453SEric Joyner 
3565*71d10453SEric Joyner 		ice_fill_tbl(hw, blk_id, hw->blk[blk_id].xlt1.sid);
3566*71d10453SEric Joyner 		ice_fill_tbl(hw, blk_id, hw->blk[blk_id].xlt2.sid);
3567*71d10453SEric Joyner 		ice_fill_tbl(hw, blk_id, hw->blk[blk_id].prof.sid);
3568*71d10453SEric Joyner 		ice_fill_tbl(hw, blk_id, hw->blk[blk_id].prof_redir.sid);
3569*71d10453SEric Joyner 		ice_fill_tbl(hw, blk_id, hw->blk[blk_id].es.sid);
3570*71d10453SEric Joyner 	}
3571*71d10453SEric Joyner 
3572*71d10453SEric Joyner 	ice_init_sw_db(hw);
3573*71d10453SEric Joyner }
3574*71d10453SEric Joyner 
3575*71d10453SEric Joyner /**
3576*71d10453SEric Joyner  * ice_free_prof_map - free profile map
3577*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3578*71d10453SEric Joyner  * @blk_idx: HW block index
3579*71d10453SEric Joyner  */
3580*71d10453SEric Joyner static void ice_free_prof_map(struct ice_hw *hw, u8 blk_idx)
3581*71d10453SEric Joyner {
3582*71d10453SEric Joyner 	struct ice_es *es = &hw->blk[blk_idx].es;
3583*71d10453SEric Joyner 	struct ice_prof_map *del, *tmp;
3584*71d10453SEric Joyner 
3585*71d10453SEric Joyner 	ice_acquire_lock(&es->prof_map_lock);
3586*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &es->prof_map,
3587*71d10453SEric Joyner 				 ice_prof_map, list) {
3588*71d10453SEric Joyner 		LIST_DEL(&del->list);
3589*71d10453SEric Joyner 		ice_free(hw, del);
3590*71d10453SEric Joyner 	}
3591*71d10453SEric Joyner 	INIT_LIST_HEAD(&es->prof_map);
3592*71d10453SEric Joyner 	ice_release_lock(&es->prof_map_lock);
3593*71d10453SEric Joyner }
3594*71d10453SEric Joyner 
3595*71d10453SEric Joyner /**
3596*71d10453SEric Joyner  * ice_free_flow_profs - free flow profile entries
3597*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3598*71d10453SEric Joyner  * @blk_idx: HW block index
3599*71d10453SEric Joyner  */
3600*71d10453SEric Joyner static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx)
3601*71d10453SEric Joyner {
3602*71d10453SEric Joyner 	struct ice_flow_prof *p, *tmp;
3603*71d10453SEric Joyner 
3604*71d10453SEric Joyner 	ice_acquire_lock(&hw->fl_profs_locks[blk_idx]);
3605*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(p, tmp, &hw->fl_profs[blk_idx],
3606*71d10453SEric Joyner 				 ice_flow_prof, l_entry) {
3607*71d10453SEric Joyner 		struct ice_flow_entry *e, *t;
3608*71d10453SEric Joyner 
3609*71d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(e, t, &p->entries,
3610*71d10453SEric Joyner 					 ice_flow_entry, l_entry)
3611*71d10453SEric Joyner 			ice_flow_rem_entry(hw, (enum ice_block)blk_idx,
3612*71d10453SEric Joyner 					   ICE_FLOW_ENTRY_HNDL(e));
3613*71d10453SEric Joyner 
3614*71d10453SEric Joyner 		LIST_DEL(&p->l_entry);
3615*71d10453SEric Joyner 		if (p->acts)
3616*71d10453SEric Joyner 			ice_free(hw, p->acts);
3617*71d10453SEric Joyner 		ice_free(hw, p);
3618*71d10453SEric Joyner 	}
3619*71d10453SEric Joyner 	ice_release_lock(&hw->fl_profs_locks[blk_idx]);
3620*71d10453SEric Joyner 
3621*71d10453SEric Joyner 	/* if driver is in reset and tables are being cleared
3622*71d10453SEric Joyner 	 * re-initialize the flow profile list heads
3623*71d10453SEric Joyner 	 */
3624*71d10453SEric Joyner 	INIT_LIST_HEAD(&hw->fl_profs[blk_idx]);
3625*71d10453SEric Joyner }
3626*71d10453SEric Joyner 
3627*71d10453SEric Joyner /**
3628*71d10453SEric Joyner  * ice_free_vsig_tbl - free complete VSIG table entries
3629*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3630*71d10453SEric Joyner  * @blk: the HW block on which to free the VSIG table entries
3631*71d10453SEric Joyner  */
3632*71d10453SEric Joyner static void ice_free_vsig_tbl(struct ice_hw *hw, enum ice_block blk)
3633*71d10453SEric Joyner {
3634*71d10453SEric Joyner 	u16 i;
3635*71d10453SEric Joyner 
3636*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl)
3637*71d10453SEric Joyner 		return;
3638*71d10453SEric Joyner 
3639*71d10453SEric Joyner 	for (i = 1; i < ICE_MAX_VSIGS; i++)
3640*71d10453SEric Joyner 		if (hw->blk[blk].xlt2.vsig_tbl[i].in_use)
3641*71d10453SEric Joyner 			ice_vsig_free(hw, blk, i);
3642*71d10453SEric Joyner }
3643*71d10453SEric Joyner 
3644*71d10453SEric Joyner /**
3645*71d10453SEric Joyner  * ice_free_hw_tbls - free hardware table memory
3646*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3647*71d10453SEric Joyner  */
3648*71d10453SEric Joyner void ice_free_hw_tbls(struct ice_hw *hw)
3649*71d10453SEric Joyner {
3650*71d10453SEric Joyner 	struct ice_rss_cfg *r, *rt;
3651*71d10453SEric Joyner 	u8 i;
3652*71d10453SEric Joyner 
3653*71d10453SEric Joyner 	for (i = 0; i < ICE_BLK_COUNT; i++) {
3654*71d10453SEric Joyner 		if (hw->blk[i].is_list_init) {
3655*71d10453SEric Joyner 			struct ice_es *es = &hw->blk[i].es;
3656*71d10453SEric Joyner 
3657*71d10453SEric Joyner 			ice_free_prof_map(hw, i);
3658*71d10453SEric Joyner 			ice_destroy_lock(&es->prof_map_lock);
3659*71d10453SEric Joyner 
3660*71d10453SEric Joyner 			ice_free_flow_profs(hw, i);
3661*71d10453SEric Joyner 			ice_destroy_lock(&hw->fl_profs_locks[i]);
3662*71d10453SEric Joyner 
3663*71d10453SEric Joyner 			hw->blk[i].is_list_init = false;
3664*71d10453SEric Joyner 		}
3665*71d10453SEric Joyner 		ice_free_vsig_tbl(hw, (enum ice_block)i);
3666*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt1.ptypes);
3667*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt1.ptg_tbl);
3668*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt1.t);
3669*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt2.t);
3670*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt2.vsig_tbl);
3671*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].xlt2.vsis);
3672*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].prof.t);
3673*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].prof_redir.t);
3674*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].es.t);
3675*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].es.ref_count);
3676*71d10453SEric Joyner 		ice_free(hw, hw->blk[i].es.written);
3677*71d10453SEric Joyner 	}
3678*71d10453SEric Joyner 
3679*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(r, rt, &hw->rss_list_head,
3680*71d10453SEric Joyner 				 ice_rss_cfg, l_entry) {
3681*71d10453SEric Joyner 		LIST_DEL(&r->l_entry);
3682*71d10453SEric Joyner 		ice_free(hw, r);
3683*71d10453SEric Joyner 	}
3684*71d10453SEric Joyner 	ice_destroy_lock(&hw->rss_locks);
3685*71d10453SEric Joyner 	ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM);
3686*71d10453SEric Joyner }
3687*71d10453SEric Joyner 
3688*71d10453SEric Joyner /**
3689*71d10453SEric Joyner  * ice_init_flow_profs - init flow profile locks and list heads
3690*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3691*71d10453SEric Joyner  * @blk_idx: HW block index
3692*71d10453SEric Joyner  */
3693*71d10453SEric Joyner static void ice_init_flow_profs(struct ice_hw *hw, u8 blk_idx)
3694*71d10453SEric Joyner {
3695*71d10453SEric Joyner 	ice_init_lock(&hw->fl_profs_locks[blk_idx]);
3696*71d10453SEric Joyner 	INIT_LIST_HEAD(&hw->fl_profs[blk_idx]);
3697*71d10453SEric Joyner }
3698*71d10453SEric Joyner 
3699*71d10453SEric Joyner /**
3700*71d10453SEric Joyner  * ice_clear_hw_tbls - clear HW tables and flow profiles
3701*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3702*71d10453SEric Joyner  */
3703*71d10453SEric Joyner void ice_clear_hw_tbls(struct ice_hw *hw)
3704*71d10453SEric Joyner {
3705*71d10453SEric Joyner 	u8 i;
3706*71d10453SEric Joyner 
3707*71d10453SEric Joyner 	for (i = 0; i < ICE_BLK_COUNT; i++) {
3708*71d10453SEric Joyner 		struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
3709*71d10453SEric Joyner 		struct ice_prof_tcam *prof = &hw->blk[i].prof;
3710*71d10453SEric Joyner 		struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1;
3711*71d10453SEric Joyner 		struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2;
3712*71d10453SEric Joyner 		struct ice_es *es = &hw->blk[i].es;
3713*71d10453SEric Joyner 
3714*71d10453SEric Joyner 		if (hw->blk[i].is_list_init) {
3715*71d10453SEric Joyner 			ice_free_prof_map(hw, i);
3716*71d10453SEric Joyner 			ice_free_flow_profs(hw, i);
3717*71d10453SEric Joyner 		}
3718*71d10453SEric Joyner 
3719*71d10453SEric Joyner 		ice_free_vsig_tbl(hw, (enum ice_block)i);
3720*71d10453SEric Joyner 
3721*71d10453SEric Joyner 		ice_memset(xlt1->ptypes, 0, xlt1->count * sizeof(*xlt1->ptypes),
3722*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3723*71d10453SEric Joyner 		ice_memset(xlt1->ptg_tbl, 0,
3724*71d10453SEric Joyner 			   ICE_MAX_PTGS * sizeof(*xlt1->ptg_tbl),
3725*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3726*71d10453SEric Joyner 		ice_memset(xlt1->t, 0, xlt1->count * sizeof(*xlt1->t),
3727*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3728*71d10453SEric Joyner 
3729*71d10453SEric Joyner 		ice_memset(xlt2->vsis, 0, xlt2->count * sizeof(*xlt2->vsis),
3730*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3731*71d10453SEric Joyner 		ice_memset(xlt2->vsig_tbl, 0,
3732*71d10453SEric Joyner 			   xlt2->count * sizeof(*xlt2->vsig_tbl),
3733*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3734*71d10453SEric Joyner 		ice_memset(xlt2->t, 0, xlt2->count * sizeof(*xlt2->t),
3735*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3736*71d10453SEric Joyner 
3737*71d10453SEric Joyner 		ice_memset(prof->t, 0, prof->count * sizeof(*prof->t),
3738*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3739*71d10453SEric Joyner 		ice_memset(prof_redir->t, 0,
3740*71d10453SEric Joyner 			   prof_redir->count * sizeof(*prof_redir->t),
3741*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3742*71d10453SEric Joyner 
3743*71d10453SEric Joyner 		ice_memset(es->t, 0, es->count * sizeof(*es->t),
3744*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3745*71d10453SEric Joyner 		ice_memset(es->ref_count, 0, es->count * sizeof(*es->ref_count),
3746*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3747*71d10453SEric Joyner 		ice_memset(es->written, 0, es->count * sizeof(*es->written),
3748*71d10453SEric Joyner 			   ICE_NONDMA_MEM);
3749*71d10453SEric Joyner 	}
3750*71d10453SEric Joyner }
3751*71d10453SEric Joyner 
3752*71d10453SEric Joyner /**
3753*71d10453SEric Joyner  * ice_init_hw_tbls - init hardware table memory
3754*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3755*71d10453SEric Joyner  */
3756*71d10453SEric Joyner enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
3757*71d10453SEric Joyner {
3758*71d10453SEric Joyner 	u8 i;
3759*71d10453SEric Joyner 
3760*71d10453SEric Joyner 	ice_init_lock(&hw->rss_locks);
3761*71d10453SEric Joyner 	INIT_LIST_HEAD(&hw->rss_list_head);
3762*71d10453SEric Joyner 	for (i = 0; i < ICE_BLK_COUNT; i++) {
3763*71d10453SEric Joyner 		struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
3764*71d10453SEric Joyner 		struct ice_prof_tcam *prof = &hw->blk[i].prof;
3765*71d10453SEric Joyner 		struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1;
3766*71d10453SEric Joyner 		struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2;
3767*71d10453SEric Joyner 		struct ice_es *es = &hw->blk[i].es;
3768*71d10453SEric Joyner 		u16 j;
3769*71d10453SEric Joyner 
3770*71d10453SEric Joyner 		if (hw->blk[i].is_list_init)
3771*71d10453SEric Joyner 			continue;
3772*71d10453SEric Joyner 
3773*71d10453SEric Joyner 		ice_init_flow_profs(hw, i);
3774*71d10453SEric Joyner 		ice_init_lock(&es->prof_map_lock);
3775*71d10453SEric Joyner 		INIT_LIST_HEAD(&es->prof_map);
3776*71d10453SEric Joyner 		hw->blk[i].is_list_init = true;
3777*71d10453SEric Joyner 
3778*71d10453SEric Joyner 		hw->blk[i].overwrite = blk_sizes[i].overwrite;
3779*71d10453SEric Joyner 		es->reverse = blk_sizes[i].reverse;
3780*71d10453SEric Joyner 
3781*71d10453SEric Joyner 		xlt1->sid = ice_blk_sids[i][ICE_SID_XLT1_OFF];
3782*71d10453SEric Joyner 		xlt1->count = blk_sizes[i].xlt1;
3783*71d10453SEric Joyner 
3784*71d10453SEric Joyner 		xlt1->ptypes = (struct ice_ptg_ptype *)
3785*71d10453SEric Joyner 			ice_calloc(hw, xlt1->count, sizeof(*xlt1->ptypes));
3786*71d10453SEric Joyner 
3787*71d10453SEric Joyner 		if (!xlt1->ptypes)
3788*71d10453SEric Joyner 			goto err;
3789*71d10453SEric Joyner 
3790*71d10453SEric Joyner 		xlt1->ptg_tbl = (struct ice_ptg_entry *)
3791*71d10453SEric Joyner 			ice_calloc(hw, ICE_MAX_PTGS, sizeof(*xlt1->ptg_tbl));
3792*71d10453SEric Joyner 
3793*71d10453SEric Joyner 		if (!xlt1->ptg_tbl)
3794*71d10453SEric Joyner 			goto err;
3795*71d10453SEric Joyner 
3796*71d10453SEric Joyner 		xlt1->t = (u8 *)ice_calloc(hw, xlt1->count, sizeof(*xlt1->t));
3797*71d10453SEric Joyner 		if (!xlt1->t)
3798*71d10453SEric Joyner 			goto err;
3799*71d10453SEric Joyner 
3800*71d10453SEric Joyner 		xlt2->sid = ice_blk_sids[i][ICE_SID_XLT2_OFF];
3801*71d10453SEric Joyner 		xlt2->count = blk_sizes[i].xlt2;
3802*71d10453SEric Joyner 
3803*71d10453SEric Joyner 		xlt2->vsis = (struct ice_vsig_vsi *)
3804*71d10453SEric Joyner 			ice_calloc(hw, xlt2->count, sizeof(*xlt2->vsis));
3805*71d10453SEric Joyner 
3806*71d10453SEric Joyner 		if (!xlt2->vsis)
3807*71d10453SEric Joyner 			goto err;
3808*71d10453SEric Joyner 
3809*71d10453SEric Joyner 		xlt2->vsig_tbl = (struct ice_vsig_entry *)
3810*71d10453SEric Joyner 			ice_calloc(hw, xlt2->count, sizeof(*xlt2->vsig_tbl));
3811*71d10453SEric Joyner 		if (!xlt2->vsig_tbl)
3812*71d10453SEric Joyner 			goto err;
3813*71d10453SEric Joyner 
3814*71d10453SEric Joyner 		for (j = 0; j < xlt2->count; j++)
3815*71d10453SEric Joyner 			INIT_LIST_HEAD(&xlt2->vsig_tbl[j].prop_lst);
3816*71d10453SEric Joyner 
3817*71d10453SEric Joyner 		xlt2->t = (u16 *)ice_calloc(hw, xlt2->count, sizeof(*xlt2->t));
3818*71d10453SEric Joyner 		if (!xlt2->t)
3819*71d10453SEric Joyner 			goto err;
3820*71d10453SEric Joyner 
3821*71d10453SEric Joyner 		prof->sid = ice_blk_sids[i][ICE_SID_PR_OFF];
3822*71d10453SEric Joyner 		prof->count = blk_sizes[i].prof_tcam;
3823*71d10453SEric Joyner 		prof->max_prof_id = blk_sizes[i].prof_id;
3824*71d10453SEric Joyner 		prof->cdid_bits = blk_sizes[i].prof_cdid_bits;
3825*71d10453SEric Joyner 		prof->t = (struct ice_prof_tcam_entry *)
3826*71d10453SEric Joyner 			ice_calloc(hw, prof->count, sizeof(*prof->t));
3827*71d10453SEric Joyner 
3828*71d10453SEric Joyner 		if (!prof->t)
3829*71d10453SEric Joyner 			goto err;
3830*71d10453SEric Joyner 
3831*71d10453SEric Joyner 		prof_redir->sid = ice_blk_sids[i][ICE_SID_PR_REDIR_OFF];
3832*71d10453SEric Joyner 		prof_redir->count = blk_sizes[i].prof_redir;
3833*71d10453SEric Joyner 		prof_redir->t = (u8 *)ice_calloc(hw, prof_redir->count,
3834*71d10453SEric Joyner 						 sizeof(*prof_redir->t));
3835*71d10453SEric Joyner 
3836*71d10453SEric Joyner 		if (!prof_redir->t)
3837*71d10453SEric Joyner 			goto err;
3838*71d10453SEric Joyner 
3839*71d10453SEric Joyner 		es->sid = ice_blk_sids[i][ICE_SID_ES_OFF];
3840*71d10453SEric Joyner 		es->count = blk_sizes[i].es;
3841*71d10453SEric Joyner 		es->fvw = blk_sizes[i].fvw;
3842*71d10453SEric Joyner 		es->t = (struct ice_fv_word *)
3843*71d10453SEric Joyner 			ice_calloc(hw, (u32)(es->count * es->fvw),
3844*71d10453SEric Joyner 				   sizeof(*es->t));
3845*71d10453SEric Joyner 		if (!es->t)
3846*71d10453SEric Joyner 			goto err;
3847*71d10453SEric Joyner 
3848*71d10453SEric Joyner 		es->ref_count = (u16 *)
3849*71d10453SEric Joyner 			ice_calloc(hw, es->count, sizeof(*es->ref_count));
3850*71d10453SEric Joyner 
3851*71d10453SEric Joyner 		es->written = (u8 *)
3852*71d10453SEric Joyner 			ice_calloc(hw, es->count, sizeof(*es->written));
3853*71d10453SEric Joyner 		if (!es->ref_count)
3854*71d10453SEric Joyner 			goto err;
3855*71d10453SEric Joyner 	}
3856*71d10453SEric Joyner 	return ICE_SUCCESS;
3857*71d10453SEric Joyner 
3858*71d10453SEric Joyner err:
3859*71d10453SEric Joyner 	ice_free_hw_tbls(hw);
3860*71d10453SEric Joyner 	return ICE_ERR_NO_MEMORY;
3861*71d10453SEric Joyner }
3862*71d10453SEric Joyner 
3863*71d10453SEric Joyner /**
3864*71d10453SEric Joyner  * ice_prof_gen_key - generate profile ID key
3865*71d10453SEric Joyner  * @hw: pointer to the HW struct
3866*71d10453SEric Joyner  * @blk: the block in which to write profile ID to
3867*71d10453SEric Joyner  * @ptg: packet type group (PTG) portion of key
3868*71d10453SEric Joyner  * @vsig: VSIG portion of key
3869*71d10453SEric Joyner  * @cdid: CDID portion of key
3870*71d10453SEric Joyner  * @flags: flag portion of key
3871*71d10453SEric Joyner  * @vl_msk: valid mask
3872*71d10453SEric Joyner  * @dc_msk: don't care mask
3873*71d10453SEric Joyner  * @nm_msk: never match mask
3874*71d10453SEric Joyner  * @key: output of profile ID key
3875*71d10453SEric Joyner  */
3876*71d10453SEric Joyner static enum ice_status
3877*71d10453SEric Joyner ice_prof_gen_key(struct ice_hw *hw, enum ice_block blk, u8 ptg, u16 vsig,
3878*71d10453SEric Joyner 		 u8 cdid, u16 flags, u8 vl_msk[ICE_TCAM_KEY_VAL_SZ],
3879*71d10453SEric Joyner 		 u8 dc_msk[ICE_TCAM_KEY_VAL_SZ], u8 nm_msk[ICE_TCAM_KEY_VAL_SZ],
3880*71d10453SEric Joyner 		 u8 key[ICE_TCAM_KEY_SZ])
3881*71d10453SEric Joyner {
3882*71d10453SEric Joyner 	struct ice_prof_id_key inkey;
3883*71d10453SEric Joyner 
3884*71d10453SEric Joyner 	inkey.xlt1 = ptg;
3885*71d10453SEric Joyner 	inkey.xlt2_cdid = CPU_TO_LE16(vsig);
3886*71d10453SEric Joyner 	inkey.flags = CPU_TO_LE16(flags);
3887*71d10453SEric Joyner 
3888*71d10453SEric Joyner 	switch (hw->blk[blk].prof.cdid_bits) {
3889*71d10453SEric Joyner 	case 0:
3890*71d10453SEric Joyner 		break;
3891*71d10453SEric Joyner 	case 2:
3892*71d10453SEric Joyner #define ICE_CD_2_M 0xC000U
3893*71d10453SEric Joyner #define ICE_CD_2_S 14
3894*71d10453SEric Joyner 		inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_2_M);
3895*71d10453SEric Joyner 		inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_2_S);
3896*71d10453SEric Joyner 		break;
3897*71d10453SEric Joyner 	case 4:
3898*71d10453SEric Joyner #define ICE_CD_4_M 0xF000U
3899*71d10453SEric Joyner #define ICE_CD_4_S 12
3900*71d10453SEric Joyner 		inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_4_M);
3901*71d10453SEric Joyner 		inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_4_S);
3902*71d10453SEric Joyner 		break;
3903*71d10453SEric Joyner 	case 8:
3904*71d10453SEric Joyner #define ICE_CD_8_M 0xFF00U
3905*71d10453SEric Joyner #define ICE_CD_8_S 16
3906*71d10453SEric Joyner 		inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_8_M);
3907*71d10453SEric Joyner 		inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_8_S);
3908*71d10453SEric Joyner 		break;
3909*71d10453SEric Joyner 	default:
3910*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "Error in profile config\n");
3911*71d10453SEric Joyner 		break;
3912*71d10453SEric Joyner 	}
3913*71d10453SEric Joyner 
3914*71d10453SEric Joyner 	return ice_set_key(key, ICE_TCAM_KEY_SZ, (u8 *)&inkey, vl_msk, dc_msk,
3915*71d10453SEric Joyner 			   nm_msk, 0, ICE_TCAM_KEY_SZ / 2);
3916*71d10453SEric Joyner }
3917*71d10453SEric Joyner 
3918*71d10453SEric Joyner /**
3919*71d10453SEric Joyner  * ice_tcam_write_entry - write TCAM entry
3920*71d10453SEric Joyner  * @hw: pointer to the HW struct
3921*71d10453SEric Joyner  * @blk: the block in which to write profile ID to
3922*71d10453SEric Joyner  * @idx: the entry index to write to
3923*71d10453SEric Joyner  * @prof_id: profile ID
3924*71d10453SEric Joyner  * @ptg: packet type group (PTG) portion of key
3925*71d10453SEric Joyner  * @vsig: VSIG portion of key
3926*71d10453SEric Joyner  * @cdid: CDID: portion of key
3927*71d10453SEric Joyner  * @flags: flag portion of key
3928*71d10453SEric Joyner  * @vl_msk: valid mask
3929*71d10453SEric Joyner  * @dc_msk: don't care mask
3930*71d10453SEric Joyner  * @nm_msk: never match mask
3931*71d10453SEric Joyner  */
3932*71d10453SEric Joyner static enum ice_status
3933*71d10453SEric Joyner ice_tcam_write_entry(struct ice_hw *hw, enum ice_block blk, u16 idx,
3934*71d10453SEric Joyner 		     u8 prof_id, u8 ptg, u16 vsig, u8 cdid, u16 flags,
3935*71d10453SEric Joyner 		     u8 vl_msk[ICE_TCAM_KEY_VAL_SZ],
3936*71d10453SEric Joyner 		     u8 dc_msk[ICE_TCAM_KEY_VAL_SZ],
3937*71d10453SEric Joyner 		     u8 nm_msk[ICE_TCAM_KEY_VAL_SZ])
3938*71d10453SEric Joyner {
3939*71d10453SEric Joyner 	struct ice_prof_tcam_entry;
3940*71d10453SEric Joyner 	enum ice_status status;
3941*71d10453SEric Joyner 
3942*71d10453SEric Joyner 	status = ice_prof_gen_key(hw, blk, ptg, vsig, cdid, flags, vl_msk,
3943*71d10453SEric Joyner 				  dc_msk, nm_msk, hw->blk[blk].prof.t[idx].key);
3944*71d10453SEric Joyner 	if (!status) {
3945*71d10453SEric Joyner 		hw->blk[blk].prof.t[idx].addr = CPU_TO_LE16(idx);
3946*71d10453SEric Joyner 		hw->blk[blk].prof.t[idx].prof_id = prof_id;
3947*71d10453SEric Joyner 	}
3948*71d10453SEric Joyner 
3949*71d10453SEric Joyner 	return status;
3950*71d10453SEric Joyner }
3951*71d10453SEric Joyner 
3952*71d10453SEric Joyner /**
3953*71d10453SEric Joyner  * ice_vsig_get_ref - returns number of VSIs belong to a VSIG
3954*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3955*71d10453SEric Joyner  * @blk: HW block
3956*71d10453SEric Joyner  * @vsig: VSIG to query
3957*71d10453SEric Joyner  * @refs: pointer to variable to receive the reference count
3958*71d10453SEric Joyner  */
3959*71d10453SEric Joyner static enum ice_status
3960*71d10453SEric Joyner ice_vsig_get_ref(struct ice_hw *hw, enum ice_block blk, u16 vsig, u16 *refs)
3961*71d10453SEric Joyner {
3962*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
3963*71d10453SEric Joyner 	struct ice_vsig_vsi *ptr;
3964*71d10453SEric Joyner 
3965*71d10453SEric Joyner 	*refs = 0;
3966*71d10453SEric Joyner 
3967*71d10453SEric Joyner 	if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
3968*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
3969*71d10453SEric Joyner 
3970*71d10453SEric Joyner 	ptr = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
3971*71d10453SEric Joyner 	while (ptr) {
3972*71d10453SEric Joyner 		(*refs)++;
3973*71d10453SEric Joyner 		ptr = ptr->next_vsi;
3974*71d10453SEric Joyner 	}
3975*71d10453SEric Joyner 
3976*71d10453SEric Joyner 	return ICE_SUCCESS;
3977*71d10453SEric Joyner }
3978*71d10453SEric Joyner 
3979*71d10453SEric Joyner /**
3980*71d10453SEric Joyner  * ice_has_prof_vsig - check to see if VSIG has a specific profile
3981*71d10453SEric Joyner  * @hw: pointer to the hardware structure
3982*71d10453SEric Joyner  * @blk: HW block
3983*71d10453SEric Joyner  * @vsig: VSIG to check against
3984*71d10453SEric Joyner  * @hdl: profile handle
3985*71d10453SEric Joyner  */
3986*71d10453SEric Joyner static bool
3987*71d10453SEric Joyner ice_has_prof_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl)
3988*71d10453SEric Joyner {
3989*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
3990*71d10453SEric Joyner 	struct ice_vsig_prof *ent;
3991*71d10453SEric Joyner 
3992*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(ent, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
3993*71d10453SEric Joyner 			    ice_vsig_prof, list) {
3994*71d10453SEric Joyner 		if (ent->profile_cookie == hdl)
3995*71d10453SEric Joyner 			return true;
3996*71d10453SEric Joyner 	}
3997*71d10453SEric Joyner 
3998*71d10453SEric Joyner 	ice_debug(hw, ICE_DBG_INIT,
3999*71d10453SEric Joyner 		  "Characteristic list for VSI group %d not found.\n",
4000*71d10453SEric Joyner 		  vsig);
4001*71d10453SEric Joyner 	return false;
4002*71d10453SEric Joyner }
4003*71d10453SEric Joyner 
4004*71d10453SEric Joyner /**
4005*71d10453SEric Joyner  * ice_prof_bld_es - build profile ID extraction sequence changes
4006*71d10453SEric Joyner  * @hw: pointer to the HW struct
4007*71d10453SEric Joyner  * @blk: hardware block
4008*71d10453SEric Joyner  * @bld: the update package buffer build to add to
4009*71d10453SEric Joyner  * @chgs: the list of changes to make in hardware
4010*71d10453SEric Joyner  */
4011*71d10453SEric Joyner static enum ice_status
4012*71d10453SEric Joyner ice_prof_bld_es(struct ice_hw *hw, enum ice_block blk,
4013*71d10453SEric Joyner 		struct ice_buf_build *bld, struct LIST_HEAD_TYPE *chgs)
4014*71d10453SEric Joyner {
4015*71d10453SEric Joyner 	u16 vec_size = hw->blk[blk].es.fvw * sizeof(struct ice_fv_word);
4016*71d10453SEric Joyner 	struct ice_chs_chg *tmp;
4017*71d10453SEric Joyner 
4018*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
4019*71d10453SEric Joyner 		if (tmp->type == ICE_PTG_ES_ADD && tmp->add_prof) {
4020*71d10453SEric Joyner 			u16 off = tmp->prof_id * hw->blk[blk].es.fvw;
4021*71d10453SEric Joyner 			struct ice_pkg_es *p;
4022*71d10453SEric Joyner 			u32 id;
4023*71d10453SEric Joyner 
4024*71d10453SEric Joyner 			id = ice_sect_id(blk, ICE_VEC_TBL);
4025*71d10453SEric Joyner 			p = (struct ice_pkg_es *)
4026*71d10453SEric Joyner 				ice_pkg_buf_alloc_section(bld, id, sizeof(*p) +
4027*71d10453SEric Joyner 							  vec_size -
4028*71d10453SEric Joyner 							  sizeof(p->es[0]));
4029*71d10453SEric Joyner 
4030*71d10453SEric Joyner 			if (!p)
4031*71d10453SEric Joyner 				return ICE_ERR_MAX_LIMIT;
4032*71d10453SEric Joyner 
4033*71d10453SEric Joyner 			p->count = CPU_TO_LE16(1);
4034*71d10453SEric Joyner 			p->offset = CPU_TO_LE16(tmp->prof_id);
4035*71d10453SEric Joyner 
4036*71d10453SEric Joyner 			ice_memcpy(p->es, &hw->blk[blk].es.t[off], vec_size,
4037*71d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
4038*71d10453SEric Joyner 		}
4039*71d10453SEric Joyner 	}
4040*71d10453SEric Joyner 
4041*71d10453SEric Joyner 	return ICE_SUCCESS;
4042*71d10453SEric Joyner }
4043*71d10453SEric Joyner 
4044*71d10453SEric Joyner /**
4045*71d10453SEric Joyner  * ice_prof_bld_tcam - build profile ID TCAM changes
4046*71d10453SEric Joyner  * @hw: pointer to the HW struct
4047*71d10453SEric Joyner  * @blk: hardware block
4048*71d10453SEric Joyner  * @bld: the update package buffer build to add to
4049*71d10453SEric Joyner  * @chgs: the list of changes to make in hardware
4050*71d10453SEric Joyner  */
4051*71d10453SEric Joyner static enum ice_status
4052*71d10453SEric Joyner ice_prof_bld_tcam(struct ice_hw *hw, enum ice_block blk,
4053*71d10453SEric Joyner 		  struct ice_buf_build *bld, struct LIST_HEAD_TYPE *chgs)
4054*71d10453SEric Joyner {
4055*71d10453SEric Joyner 	struct ice_chs_chg *tmp;
4056*71d10453SEric Joyner 
4057*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
4058*71d10453SEric Joyner 		if (tmp->type == ICE_TCAM_ADD && tmp->add_tcam_idx) {
4059*71d10453SEric Joyner 			struct ice_prof_id_section *p;
4060*71d10453SEric Joyner 			u32 id;
4061*71d10453SEric Joyner 
4062*71d10453SEric Joyner 			id = ice_sect_id(blk, ICE_PROF_TCAM);
4063*71d10453SEric Joyner 			p = (struct ice_prof_id_section *)
4064*71d10453SEric Joyner 				ice_pkg_buf_alloc_section(bld, id, sizeof(*p));
4065*71d10453SEric Joyner 
4066*71d10453SEric Joyner 			if (!p)
4067*71d10453SEric Joyner 				return ICE_ERR_MAX_LIMIT;
4068*71d10453SEric Joyner 
4069*71d10453SEric Joyner 			p->count = CPU_TO_LE16(1);
4070*71d10453SEric Joyner 			p->entry[0].addr = CPU_TO_LE16(tmp->tcam_idx);
4071*71d10453SEric Joyner 			p->entry[0].prof_id = tmp->prof_id;
4072*71d10453SEric Joyner 
4073*71d10453SEric Joyner 			ice_memcpy(p->entry[0].key,
4074*71d10453SEric Joyner 				   &hw->blk[blk].prof.t[tmp->tcam_idx].key,
4075*71d10453SEric Joyner 				   sizeof(hw->blk[blk].prof.t->key),
4076*71d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
4077*71d10453SEric Joyner 		}
4078*71d10453SEric Joyner 	}
4079*71d10453SEric Joyner 
4080*71d10453SEric Joyner 	return ICE_SUCCESS;
4081*71d10453SEric Joyner }
4082*71d10453SEric Joyner 
4083*71d10453SEric Joyner /**
4084*71d10453SEric Joyner  * ice_prof_bld_xlt1 - build XLT1 changes
4085*71d10453SEric Joyner  * @blk: hardware block
4086*71d10453SEric Joyner  * @bld: the update package buffer build to add to
4087*71d10453SEric Joyner  * @chgs: the list of changes to make in hardware
4088*71d10453SEric Joyner  */
4089*71d10453SEric Joyner static enum ice_status
4090*71d10453SEric Joyner ice_prof_bld_xlt1(enum ice_block blk, struct ice_buf_build *bld,
4091*71d10453SEric Joyner 		  struct LIST_HEAD_TYPE *chgs)
4092*71d10453SEric Joyner {
4093*71d10453SEric Joyner 	struct ice_chs_chg *tmp;
4094*71d10453SEric Joyner 
4095*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
4096*71d10453SEric Joyner 		if (tmp->type == ICE_PTG_ES_ADD && tmp->add_ptg) {
4097*71d10453SEric Joyner 			struct ice_xlt1_section *p;
4098*71d10453SEric Joyner 			u32 id;
4099*71d10453SEric Joyner 
4100*71d10453SEric Joyner 			id = ice_sect_id(blk, ICE_XLT1);
4101*71d10453SEric Joyner 			p = (struct ice_xlt1_section *)
4102*71d10453SEric Joyner 				ice_pkg_buf_alloc_section(bld, id, sizeof(*p));
4103*71d10453SEric Joyner 
4104*71d10453SEric Joyner 			if (!p)
4105*71d10453SEric Joyner 				return ICE_ERR_MAX_LIMIT;
4106*71d10453SEric Joyner 
4107*71d10453SEric Joyner 			p->count = CPU_TO_LE16(1);
4108*71d10453SEric Joyner 			p->offset = CPU_TO_LE16(tmp->ptype);
4109*71d10453SEric Joyner 			p->value[0] = tmp->ptg;
4110*71d10453SEric Joyner 		}
4111*71d10453SEric Joyner 	}
4112*71d10453SEric Joyner 
4113*71d10453SEric Joyner 	return ICE_SUCCESS;
4114*71d10453SEric Joyner }
4115*71d10453SEric Joyner 
4116*71d10453SEric Joyner /**
4117*71d10453SEric Joyner  * ice_prof_bld_xlt2 - build XLT2 changes
4118*71d10453SEric Joyner  * @blk: hardware block
4119*71d10453SEric Joyner  * @bld: the update package buffer build to add to
4120*71d10453SEric Joyner  * @chgs: the list of changes to make in hardware
4121*71d10453SEric Joyner  */
4122*71d10453SEric Joyner static enum ice_status
4123*71d10453SEric Joyner ice_prof_bld_xlt2(enum ice_block blk, struct ice_buf_build *bld,
4124*71d10453SEric Joyner 		  struct LIST_HEAD_TYPE *chgs)
4125*71d10453SEric Joyner {
4126*71d10453SEric Joyner 	struct ice_chs_chg *tmp;
4127*71d10453SEric Joyner 
4128*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
4129*71d10453SEric Joyner 		struct ice_xlt2_section *p;
4130*71d10453SEric Joyner 		u32 id;
4131*71d10453SEric Joyner 
4132*71d10453SEric Joyner 		switch (tmp->type) {
4133*71d10453SEric Joyner 		case ICE_VSIG_ADD:
4134*71d10453SEric Joyner 		case ICE_VSI_MOVE:
4135*71d10453SEric Joyner 		case ICE_VSIG_REM:
4136*71d10453SEric Joyner 			id = ice_sect_id(blk, ICE_XLT2);
4137*71d10453SEric Joyner 			p = (struct ice_xlt2_section *)
4138*71d10453SEric Joyner 				ice_pkg_buf_alloc_section(bld, id, sizeof(*p));
4139*71d10453SEric Joyner 
4140*71d10453SEric Joyner 			if (!p)
4141*71d10453SEric Joyner 				return ICE_ERR_MAX_LIMIT;
4142*71d10453SEric Joyner 
4143*71d10453SEric Joyner 			p->count = CPU_TO_LE16(1);
4144*71d10453SEric Joyner 			p->offset = CPU_TO_LE16(tmp->vsi);
4145*71d10453SEric Joyner 			p->value[0] = CPU_TO_LE16(tmp->vsig);
4146*71d10453SEric Joyner 			break;
4147*71d10453SEric Joyner 		default:
4148*71d10453SEric Joyner 			break;
4149*71d10453SEric Joyner 		}
4150*71d10453SEric Joyner 	}
4151*71d10453SEric Joyner 
4152*71d10453SEric Joyner 	return ICE_SUCCESS;
4153*71d10453SEric Joyner }
4154*71d10453SEric Joyner 
4155*71d10453SEric Joyner /**
4156*71d10453SEric Joyner  * ice_upd_prof_hw - update hardware using the change list
4157*71d10453SEric Joyner  * @hw: pointer to the HW struct
4158*71d10453SEric Joyner  * @blk: hardware block
4159*71d10453SEric Joyner  * @chgs: the list of changes to make in hardware
4160*71d10453SEric Joyner  */
4161*71d10453SEric Joyner static enum ice_status
4162*71d10453SEric Joyner ice_upd_prof_hw(struct ice_hw *hw, enum ice_block blk,
4163*71d10453SEric Joyner 		struct LIST_HEAD_TYPE *chgs)
4164*71d10453SEric Joyner {
4165*71d10453SEric Joyner 	struct ice_buf_build *b;
4166*71d10453SEric Joyner 	struct ice_chs_chg *tmp;
4167*71d10453SEric Joyner 	enum ice_status status;
4168*71d10453SEric Joyner 	u16 pkg_sects;
4169*71d10453SEric Joyner 	u16 xlt1 = 0;
4170*71d10453SEric Joyner 	u16 xlt2 = 0;
4171*71d10453SEric Joyner 	u16 tcam = 0;
4172*71d10453SEric Joyner 	u16 es = 0;
4173*71d10453SEric Joyner 	u16 sects;
4174*71d10453SEric Joyner 
4175*71d10453SEric Joyner 	/* count number of sections we need */
4176*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
4177*71d10453SEric Joyner 		switch (tmp->type) {
4178*71d10453SEric Joyner 		case ICE_PTG_ES_ADD:
4179*71d10453SEric Joyner 			if (tmp->add_ptg)
4180*71d10453SEric Joyner 				xlt1++;
4181*71d10453SEric Joyner 			if (tmp->add_prof)
4182*71d10453SEric Joyner 				es++;
4183*71d10453SEric Joyner 			break;
4184*71d10453SEric Joyner 		case ICE_TCAM_ADD:
4185*71d10453SEric Joyner 			tcam++;
4186*71d10453SEric Joyner 			break;
4187*71d10453SEric Joyner 		case ICE_VSIG_ADD:
4188*71d10453SEric Joyner 		case ICE_VSI_MOVE:
4189*71d10453SEric Joyner 		case ICE_VSIG_REM:
4190*71d10453SEric Joyner 			xlt2++;
4191*71d10453SEric Joyner 			break;
4192*71d10453SEric Joyner 		default:
4193*71d10453SEric Joyner 			break;
4194*71d10453SEric Joyner 		}
4195*71d10453SEric Joyner 	}
4196*71d10453SEric Joyner 	sects = xlt1 + xlt2 + tcam + es;
4197*71d10453SEric Joyner 
4198*71d10453SEric Joyner 	if (!sects)
4199*71d10453SEric Joyner 		return ICE_SUCCESS;
4200*71d10453SEric Joyner 
4201*71d10453SEric Joyner 	/* Build update package buffer */
4202*71d10453SEric Joyner 	b = ice_pkg_buf_alloc(hw);
4203*71d10453SEric Joyner 	if (!b)
4204*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
4205*71d10453SEric Joyner 
4206*71d10453SEric Joyner 	status = ice_pkg_buf_reserve_section(b, sects);
4207*71d10453SEric Joyner 	if (status)
4208*71d10453SEric Joyner 		goto error_tmp;
4209*71d10453SEric Joyner 
4210*71d10453SEric Joyner 	/* Preserve order of table update: ES, TCAM, PTG, VSIG */
4211*71d10453SEric Joyner 	if (es) {
4212*71d10453SEric Joyner 		status = ice_prof_bld_es(hw, blk, b, chgs);
4213*71d10453SEric Joyner 		if (status)
4214*71d10453SEric Joyner 			goto error_tmp;
4215*71d10453SEric Joyner 	}
4216*71d10453SEric Joyner 
4217*71d10453SEric Joyner 	if (tcam) {
4218*71d10453SEric Joyner 		status = ice_prof_bld_tcam(hw, blk, b, chgs);
4219*71d10453SEric Joyner 		if (status)
4220*71d10453SEric Joyner 			goto error_tmp;
4221*71d10453SEric Joyner 	}
4222*71d10453SEric Joyner 
4223*71d10453SEric Joyner 	if (xlt1) {
4224*71d10453SEric Joyner 		status = ice_prof_bld_xlt1(blk, b, chgs);
4225*71d10453SEric Joyner 		if (status)
4226*71d10453SEric Joyner 			goto error_tmp;
4227*71d10453SEric Joyner 	}
4228*71d10453SEric Joyner 
4229*71d10453SEric Joyner 	if (xlt2) {
4230*71d10453SEric Joyner 		status = ice_prof_bld_xlt2(blk, b, chgs);
4231*71d10453SEric Joyner 		if (status)
4232*71d10453SEric Joyner 			goto error_tmp;
4233*71d10453SEric Joyner 	}
4234*71d10453SEric Joyner 
4235*71d10453SEric Joyner 	/* After package buffer build check if the section count in buffer is
4236*71d10453SEric Joyner 	 * non-zero and matches the number of sections detected for package
4237*71d10453SEric Joyner 	 * update.
4238*71d10453SEric Joyner 	 */
4239*71d10453SEric Joyner 	pkg_sects = ice_pkg_buf_get_active_sections(b);
4240*71d10453SEric Joyner 	if (!pkg_sects || pkg_sects != sects) {
4241*71d10453SEric Joyner 		status = ICE_ERR_INVAL_SIZE;
4242*71d10453SEric Joyner 		goto error_tmp;
4243*71d10453SEric Joyner 	}
4244*71d10453SEric Joyner 
4245*71d10453SEric Joyner 	/* update package */
4246*71d10453SEric Joyner 	status = ice_update_pkg(hw, ice_pkg_buf(b), 1);
4247*71d10453SEric Joyner 	if (status == ICE_ERR_AQ_ERROR)
4248*71d10453SEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "Unable to update HW profile\n");
4249*71d10453SEric Joyner 
4250*71d10453SEric Joyner error_tmp:
4251*71d10453SEric Joyner 	ice_pkg_buf_free(hw, b);
4252*71d10453SEric Joyner 	return status;
4253*71d10453SEric Joyner }
4254*71d10453SEric Joyner 
4255*71d10453SEric Joyner /**
4256*71d10453SEric Joyner  * ice_add_prof - add profile
4257*71d10453SEric Joyner  * @hw: pointer to the HW struct
4258*71d10453SEric Joyner  * @blk: hardware block
4259*71d10453SEric Joyner  * @id: profile tracking ID
4260*71d10453SEric Joyner  * @ptypes: array of bitmaps indicating ptypes (ICE_FLOW_PTYPE_MAX bits)
4261*71d10453SEric Joyner  * @es: extraction sequence (length of array is determined by the block)
4262*71d10453SEric Joyner  *
4263*71d10453SEric Joyner  * This function registers a profile, which matches a set of PTGs with a
4264*71d10453SEric Joyner  * particular extraction sequence. While the hardware profile is allocated
4265*71d10453SEric Joyner  * it will not be written until the first call to ice_add_flow that specifies
4266*71d10453SEric Joyner  * the ID value used here.
4267*71d10453SEric Joyner  */
4268*71d10453SEric Joyner enum ice_status
4269*71d10453SEric Joyner ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
4270*71d10453SEric Joyner 	     struct ice_fv_word *es)
4271*71d10453SEric Joyner {
4272*71d10453SEric Joyner 	u32 bytes = DIVIDE_AND_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
4273*71d10453SEric Joyner 	ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
4274*71d10453SEric Joyner 	struct ice_prof_map *prof;
4275*71d10453SEric Joyner 	enum ice_status status;
4276*71d10453SEric Joyner 	u8 byte = 0;
4277*71d10453SEric Joyner 	u8 prof_id;
4278*71d10453SEric Joyner 
4279*71d10453SEric Joyner 	ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
4280*71d10453SEric Joyner 
4281*71d10453SEric Joyner 	ice_acquire_lock(&hw->blk[blk].es.prof_map_lock);
4282*71d10453SEric Joyner 
4283*71d10453SEric Joyner 	/* search for existing profile */
4284*71d10453SEric Joyner 	status = ice_find_prof_id(hw, blk, es, &prof_id);
4285*71d10453SEric Joyner 	if (status) {
4286*71d10453SEric Joyner 		/* allocate profile ID */
4287*71d10453SEric Joyner 		status = ice_alloc_prof_id(hw, blk, &prof_id);
4288*71d10453SEric Joyner 		if (status)
4289*71d10453SEric Joyner 			goto err_ice_add_prof;
4290*71d10453SEric Joyner 
4291*71d10453SEric Joyner 		/* and write new es */
4292*71d10453SEric Joyner 		ice_write_es(hw, blk, prof_id, es);
4293*71d10453SEric Joyner 	}
4294*71d10453SEric Joyner 
4295*71d10453SEric Joyner 	ice_prof_inc_ref(hw, blk, prof_id);
4296*71d10453SEric Joyner 
4297*71d10453SEric Joyner 	/* add profile info */
4298*71d10453SEric Joyner 
4299*71d10453SEric Joyner 	prof = (struct ice_prof_map *)ice_malloc(hw, sizeof(*prof));
4300*71d10453SEric Joyner 	if (!prof)
4301*71d10453SEric Joyner 		goto err_ice_add_prof;
4302*71d10453SEric Joyner 
4303*71d10453SEric Joyner 	prof->profile_cookie = id;
4304*71d10453SEric Joyner 	prof->prof_id = prof_id;
4305*71d10453SEric Joyner 	prof->ptg_cnt = 0;
4306*71d10453SEric Joyner 	prof->context = 0;
4307*71d10453SEric Joyner 
4308*71d10453SEric Joyner 	/* build list of ptgs */
4309*71d10453SEric Joyner 	while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
4310*71d10453SEric Joyner 		u8 bit;
4311*71d10453SEric Joyner 
4312*71d10453SEric Joyner 		if (!ptypes[byte]) {
4313*71d10453SEric Joyner 			bytes--;
4314*71d10453SEric Joyner 			byte++;
4315*71d10453SEric Joyner 			continue;
4316*71d10453SEric Joyner 		}
4317*71d10453SEric Joyner 		/* Examine 8 bits per byte */
4318*71d10453SEric Joyner 		for (bit = 0; bit < 8; bit++) {
4319*71d10453SEric Joyner 			if (ptypes[byte] & BIT(bit)) {
4320*71d10453SEric Joyner 				u16 ptype;
4321*71d10453SEric Joyner 				u8 ptg;
4322*71d10453SEric Joyner 				u8 m;
4323*71d10453SEric Joyner 
4324*71d10453SEric Joyner 				ptype = byte * BITS_PER_BYTE + bit;
4325*71d10453SEric Joyner 
4326*71d10453SEric Joyner 				/* The package should place all ptypes in a
4327*71d10453SEric Joyner 				 * non-zero PTG, so the following call should
4328*71d10453SEric Joyner 				 * never fail.
4329*71d10453SEric Joyner 				 */
4330*71d10453SEric Joyner 				if (ice_ptg_find_ptype(hw, blk, ptype, &ptg))
4331*71d10453SEric Joyner 					continue;
4332*71d10453SEric Joyner 
4333*71d10453SEric Joyner 				/* If PTG is already added, skip and continue */
4334*71d10453SEric Joyner 				if (ice_is_bit_set(ptgs_used, ptg))
4335*71d10453SEric Joyner 					continue;
4336*71d10453SEric Joyner 
4337*71d10453SEric Joyner 				ice_set_bit(ptg, ptgs_used);
4338*71d10453SEric Joyner 				prof->ptg[prof->ptg_cnt] = ptg;
4339*71d10453SEric Joyner 
4340*71d10453SEric Joyner 				if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
4341*71d10453SEric Joyner 					break;
4342*71d10453SEric Joyner 
4343*71d10453SEric Joyner 				/* nothing left in byte, then exit */
4344*71d10453SEric Joyner 				m = ~(u8)((1 << (bit + 1)) - 1);
4345*71d10453SEric Joyner 				if (!(ptypes[byte] & m))
4346*71d10453SEric Joyner 					break;
4347*71d10453SEric Joyner 			}
4348*71d10453SEric Joyner 		}
4349*71d10453SEric Joyner 
4350*71d10453SEric Joyner 		bytes--;
4351*71d10453SEric Joyner 		byte++;
4352*71d10453SEric Joyner 	}
4353*71d10453SEric Joyner 
4354*71d10453SEric Joyner 	LIST_ADD(&prof->list, &hw->blk[blk].es.prof_map);
4355*71d10453SEric Joyner 	status = ICE_SUCCESS;
4356*71d10453SEric Joyner 
4357*71d10453SEric Joyner err_ice_add_prof:
4358*71d10453SEric Joyner 	ice_release_lock(&hw->blk[blk].es.prof_map_lock);
4359*71d10453SEric Joyner 	return status;
4360*71d10453SEric Joyner }
4361*71d10453SEric Joyner 
4362*71d10453SEric Joyner /**
4363*71d10453SEric Joyner  * ice_search_prof_id_low - Search for a profile tracking ID low level
4364*71d10453SEric Joyner  * @hw: pointer to the HW struct
4365*71d10453SEric Joyner  * @blk: hardware block
4366*71d10453SEric Joyner  * @id: profile tracking ID
4367*71d10453SEric Joyner  *
4368*71d10453SEric Joyner  * This will search for a profile tracking ID which was previously added. This
4369*71d10453SEric Joyner  * version assumes that the caller has already acquired the prof map lock.
4370*71d10453SEric Joyner  */
4371*71d10453SEric Joyner static struct ice_prof_map *
4372*71d10453SEric Joyner ice_search_prof_id_low(struct ice_hw *hw, enum ice_block blk, u64 id)
4373*71d10453SEric Joyner {
4374*71d10453SEric Joyner 	struct ice_prof_map *entry = NULL;
4375*71d10453SEric Joyner 	struct ice_prof_map *map;
4376*71d10453SEric Joyner 
4377*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(map, &hw->blk[blk].es.prof_map, ice_prof_map,
4378*71d10453SEric Joyner 			    list) {
4379*71d10453SEric Joyner 		if (map->profile_cookie == id) {
4380*71d10453SEric Joyner 			entry = map;
4381*71d10453SEric Joyner 			break;
4382*71d10453SEric Joyner 		}
4383*71d10453SEric Joyner 	}
4384*71d10453SEric Joyner 
4385*71d10453SEric Joyner 	return entry;
4386*71d10453SEric Joyner }
4387*71d10453SEric Joyner 
4388*71d10453SEric Joyner /**
4389*71d10453SEric Joyner  * ice_search_prof_id - Search for a profile tracking ID
4390*71d10453SEric Joyner  * @hw: pointer to the HW struct
4391*71d10453SEric Joyner  * @blk: hardware block
4392*71d10453SEric Joyner  * @id: profile tracking ID
4393*71d10453SEric Joyner  *
4394*71d10453SEric Joyner  * This will search for a profile tracking ID which was previously added.
4395*71d10453SEric Joyner  */
4396*71d10453SEric Joyner struct ice_prof_map *
4397*71d10453SEric Joyner ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id)
4398*71d10453SEric Joyner {
4399*71d10453SEric Joyner 	struct ice_prof_map *entry;
4400*71d10453SEric Joyner 
4401*71d10453SEric Joyner 	ice_acquire_lock(&hw->blk[blk].es.prof_map_lock);
4402*71d10453SEric Joyner 	entry = ice_search_prof_id_low(hw, blk, id);
4403*71d10453SEric Joyner 	ice_release_lock(&hw->blk[blk].es.prof_map_lock);
4404*71d10453SEric Joyner 
4405*71d10453SEric Joyner 	return entry;
4406*71d10453SEric Joyner }
4407*71d10453SEric Joyner 
4408*71d10453SEric Joyner /**
4409*71d10453SEric Joyner  * ice_set_prof_context - Set context for a given profile
4410*71d10453SEric Joyner  * @hw: pointer to the HW struct
4411*71d10453SEric Joyner  * @blk: hardware block
4412*71d10453SEric Joyner  * @id: profile tracking ID
4413*71d10453SEric Joyner  * @cntxt: context
4414*71d10453SEric Joyner  */
4415*71d10453SEric Joyner struct ice_prof_map *
4416*71d10453SEric Joyner ice_set_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 cntxt)
4417*71d10453SEric Joyner {
4418*71d10453SEric Joyner 	struct ice_prof_map *entry;
4419*71d10453SEric Joyner 
4420*71d10453SEric Joyner 	entry = ice_search_prof_id(hw, blk, id);
4421*71d10453SEric Joyner 	if (entry)
4422*71d10453SEric Joyner 		entry->context = cntxt;
4423*71d10453SEric Joyner 
4424*71d10453SEric Joyner 	return entry;
4425*71d10453SEric Joyner }
4426*71d10453SEric Joyner 
4427*71d10453SEric Joyner /**
4428*71d10453SEric Joyner  * ice_get_prof_context - Get context for a given profile
4429*71d10453SEric Joyner  * @hw: pointer to the HW struct
4430*71d10453SEric Joyner  * @blk: hardware block
4431*71d10453SEric Joyner  * @id: profile tracking ID
4432*71d10453SEric Joyner  * @cntxt: pointer to variable to receive the context
4433*71d10453SEric Joyner  */
4434*71d10453SEric Joyner struct ice_prof_map *
4435*71d10453SEric Joyner ice_get_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 *cntxt)
4436*71d10453SEric Joyner {
4437*71d10453SEric Joyner 	struct ice_prof_map *entry;
4438*71d10453SEric Joyner 
4439*71d10453SEric Joyner 	entry = ice_search_prof_id(hw, blk, id);
4440*71d10453SEric Joyner 	if (entry)
4441*71d10453SEric Joyner 		*cntxt = entry->context;
4442*71d10453SEric Joyner 
4443*71d10453SEric Joyner 	return entry;
4444*71d10453SEric Joyner }
4445*71d10453SEric Joyner 
4446*71d10453SEric Joyner /**
4447*71d10453SEric Joyner  * ice_vsig_prof_id_count - count profiles in a VSIG
4448*71d10453SEric Joyner  * @hw: pointer to the HW struct
4449*71d10453SEric Joyner  * @blk: hardware block
4450*71d10453SEric Joyner  * @vsig: VSIG to remove the profile from
4451*71d10453SEric Joyner  */
4452*71d10453SEric Joyner static u16
4453*71d10453SEric Joyner ice_vsig_prof_id_count(struct ice_hw *hw, enum ice_block blk, u16 vsig)
4454*71d10453SEric Joyner {
4455*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M, count = 0;
4456*71d10453SEric Joyner 	struct ice_vsig_prof *p;
4457*71d10453SEric Joyner 
4458*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(p, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
4459*71d10453SEric Joyner 			    ice_vsig_prof, list) {
4460*71d10453SEric Joyner 		count++;
4461*71d10453SEric Joyner 	}
4462*71d10453SEric Joyner 
4463*71d10453SEric Joyner 	return count;
4464*71d10453SEric Joyner }
4465*71d10453SEric Joyner 
4466*71d10453SEric Joyner /**
4467*71d10453SEric Joyner  * ice_rel_tcam_idx - release a TCAM index
4468*71d10453SEric Joyner  * @hw: pointer to the HW struct
4469*71d10453SEric Joyner  * @blk: hardware block
4470*71d10453SEric Joyner  * @idx: the index to release
4471*71d10453SEric Joyner  */
4472*71d10453SEric Joyner static enum ice_status
4473*71d10453SEric Joyner ice_rel_tcam_idx(struct ice_hw *hw, enum ice_block blk, u16 idx)
4474*71d10453SEric Joyner {
4475*71d10453SEric Joyner 	/* Masks to invoke a never match entry */
4476*71d10453SEric Joyner 	u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4477*71d10453SEric Joyner 	u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF };
4478*71d10453SEric Joyner 	u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };
4479*71d10453SEric Joyner 	enum ice_status status;
4480*71d10453SEric Joyner 
4481*71d10453SEric Joyner 	/* write the TCAM entry */
4482*71d10453SEric Joyner 	status = ice_tcam_write_entry(hw, blk, idx, 0, 0, 0, 0, 0, vl_msk,
4483*71d10453SEric Joyner 				      dc_msk, nm_msk);
4484*71d10453SEric Joyner 	if (status)
4485*71d10453SEric Joyner 		return status;
4486*71d10453SEric Joyner 
4487*71d10453SEric Joyner 	/* release the TCAM entry */
4488*71d10453SEric Joyner 	status = ice_free_tcam_ent(hw, blk, idx);
4489*71d10453SEric Joyner 
4490*71d10453SEric Joyner 	return status;
4491*71d10453SEric Joyner }
4492*71d10453SEric Joyner 
4493*71d10453SEric Joyner /**
4494*71d10453SEric Joyner  * ice_rem_prof_id - remove one profile from a VSIG
4495*71d10453SEric Joyner  * @hw: pointer to the HW struct
4496*71d10453SEric Joyner  * @blk: hardware block
4497*71d10453SEric Joyner  * @prof: pointer to profile structure to remove
4498*71d10453SEric Joyner  */
4499*71d10453SEric Joyner static enum ice_status
4500*71d10453SEric Joyner ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk,
4501*71d10453SEric Joyner 		struct ice_vsig_prof *prof)
4502*71d10453SEric Joyner {
4503*71d10453SEric Joyner 	enum ice_status status;
4504*71d10453SEric Joyner 	u16 i;
4505*71d10453SEric Joyner 
4506*71d10453SEric Joyner 	for (i = 0; i < prof->tcam_count; i++) {
4507*71d10453SEric Joyner 		if (prof->tcam[i].in_use) {
4508*71d10453SEric Joyner 			prof->tcam[i].in_use = false;
4509*71d10453SEric Joyner 			status = ice_rel_tcam_idx(hw, blk,
4510*71d10453SEric Joyner 						  prof->tcam[i].tcam_idx);
4511*71d10453SEric Joyner 			if (status)
4512*71d10453SEric Joyner 				return ICE_ERR_HW_TABLE;
4513*71d10453SEric Joyner 		}
4514*71d10453SEric Joyner 	}
4515*71d10453SEric Joyner 
4516*71d10453SEric Joyner 	return ICE_SUCCESS;
4517*71d10453SEric Joyner }
4518*71d10453SEric Joyner 
4519*71d10453SEric Joyner /**
4520*71d10453SEric Joyner  * ice_rem_vsig - remove VSIG
4521*71d10453SEric Joyner  * @hw: pointer to the HW struct
4522*71d10453SEric Joyner  * @blk: hardware block
4523*71d10453SEric Joyner  * @vsig: the VSIG to remove
4524*71d10453SEric Joyner  * @chg: the change list
4525*71d10453SEric Joyner  */
4526*71d10453SEric Joyner static enum ice_status
4527*71d10453SEric Joyner ice_rem_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,
4528*71d10453SEric Joyner 	     struct LIST_HEAD_TYPE *chg)
4529*71d10453SEric Joyner {
4530*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
4531*71d10453SEric Joyner 	struct ice_vsig_vsi *vsi_cur;
4532*71d10453SEric Joyner 	struct ice_vsig_prof *d, *t;
4533*71d10453SEric Joyner 	enum ice_status status;
4534*71d10453SEric Joyner 
4535*71d10453SEric Joyner 	/* remove TCAM entries */
4536*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(d, t,
4537*71d10453SEric Joyner 				 &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
4538*71d10453SEric Joyner 				 ice_vsig_prof, list) {
4539*71d10453SEric Joyner 		status = ice_rem_prof_id(hw, blk, d);
4540*71d10453SEric Joyner 		if (status)
4541*71d10453SEric Joyner 			return status;
4542*71d10453SEric Joyner 
4543*71d10453SEric Joyner 		LIST_DEL(&d->list);
4544*71d10453SEric Joyner 		ice_free(hw, d);
4545*71d10453SEric Joyner 	}
4546*71d10453SEric Joyner 
4547*71d10453SEric Joyner 	/* Move all VSIS associated with this VSIG to the default VSIG */
4548*71d10453SEric Joyner 	vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
4549*71d10453SEric Joyner 	/* If the VSIG has at least 1 VSI then iterate through the list
4550*71d10453SEric Joyner 	 * and remove the VSIs before deleting the group.
4551*71d10453SEric Joyner 	 */
4552*71d10453SEric Joyner 	if (vsi_cur) {
4553*71d10453SEric Joyner 		do {
4554*71d10453SEric Joyner 			struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
4555*71d10453SEric Joyner 			struct ice_chs_chg *p;
4556*71d10453SEric Joyner 
4557*71d10453SEric Joyner 			p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
4558*71d10453SEric Joyner 			if (!p)
4559*71d10453SEric Joyner 				return ICE_ERR_NO_MEMORY;
4560*71d10453SEric Joyner 
4561*71d10453SEric Joyner 			p->type = ICE_VSIG_REM;
4562*71d10453SEric Joyner 			p->orig_vsig = vsig;
4563*71d10453SEric Joyner 			p->vsig = ICE_DEFAULT_VSIG;
4564*71d10453SEric Joyner 			p->vsi = vsi_cur - hw->blk[blk].xlt2.vsis;
4565*71d10453SEric Joyner 
4566*71d10453SEric Joyner 			LIST_ADD(&p->list_entry, chg);
4567*71d10453SEric Joyner 
4568*71d10453SEric Joyner 			vsi_cur = tmp;
4569*71d10453SEric Joyner 		} while (vsi_cur);
4570*71d10453SEric Joyner 	}
4571*71d10453SEric Joyner 
4572*71d10453SEric Joyner 	return ice_vsig_free(hw, blk, vsig);
4573*71d10453SEric Joyner }
4574*71d10453SEric Joyner 
4575*71d10453SEric Joyner /**
4576*71d10453SEric Joyner  * ice_rem_prof_id_vsig - remove a specific profile from a VSIG
4577*71d10453SEric Joyner  * @hw: pointer to the HW struct
4578*71d10453SEric Joyner  * @blk: hardware block
4579*71d10453SEric Joyner  * @vsig: VSIG to remove the profile from
4580*71d10453SEric Joyner  * @hdl: profile handle indicating which profile to remove
4581*71d10453SEric Joyner  * @chg: list to receive a record of changes
4582*71d10453SEric Joyner  */
4583*71d10453SEric Joyner static enum ice_status
4584*71d10453SEric Joyner ice_rem_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
4585*71d10453SEric Joyner 		     struct LIST_HEAD_TYPE *chg)
4586*71d10453SEric Joyner {
4587*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
4588*71d10453SEric Joyner 	struct ice_vsig_prof *p, *t;
4589*71d10453SEric Joyner 	enum ice_status status;
4590*71d10453SEric Joyner 
4591*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(p, t,
4592*71d10453SEric Joyner 				 &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
4593*71d10453SEric Joyner 				 ice_vsig_prof, list) {
4594*71d10453SEric Joyner 		if (p->profile_cookie == hdl) {
4595*71d10453SEric Joyner 			if (ice_vsig_prof_id_count(hw, blk, vsig) == 1)
4596*71d10453SEric Joyner 				/* this is the last profile, remove the VSIG */
4597*71d10453SEric Joyner 				return ice_rem_vsig(hw, blk, vsig, chg);
4598*71d10453SEric Joyner 
4599*71d10453SEric Joyner 			status = ice_rem_prof_id(hw, blk, p);
4600*71d10453SEric Joyner 			if (!status) {
4601*71d10453SEric Joyner 				LIST_DEL(&p->list);
4602*71d10453SEric Joyner 				ice_free(hw, p);
4603*71d10453SEric Joyner 			}
4604*71d10453SEric Joyner 			return status;
4605*71d10453SEric Joyner 		}
4606*71d10453SEric Joyner 	}
4607*71d10453SEric Joyner 
4608*71d10453SEric Joyner 	return ICE_ERR_DOES_NOT_EXIST;
4609*71d10453SEric Joyner }
4610*71d10453SEric Joyner 
4611*71d10453SEric Joyner /**
4612*71d10453SEric Joyner  * ice_rem_flow_all - remove all flows with a particular profile
4613*71d10453SEric Joyner  * @hw: pointer to the HW struct
4614*71d10453SEric Joyner  * @blk: hardware block
4615*71d10453SEric Joyner  * @id: profile tracking ID
4616*71d10453SEric Joyner  */
4617*71d10453SEric Joyner static enum ice_status
4618*71d10453SEric Joyner ice_rem_flow_all(struct ice_hw *hw, enum ice_block blk, u64 id)
4619*71d10453SEric Joyner {
4620*71d10453SEric Joyner 	struct ice_chs_chg *del, *tmp;
4621*71d10453SEric Joyner 	struct LIST_HEAD_TYPE chg;
4622*71d10453SEric Joyner 	enum ice_status status;
4623*71d10453SEric Joyner 	u16 i;
4624*71d10453SEric Joyner 
4625*71d10453SEric Joyner 	INIT_LIST_HEAD(&chg);
4626*71d10453SEric Joyner 
4627*71d10453SEric Joyner 	for (i = 1; i < ICE_MAX_VSIGS; i++) {
4628*71d10453SEric Joyner 		if (hw->blk[blk].xlt2.vsig_tbl[i].in_use) {
4629*71d10453SEric Joyner 			if (ice_has_prof_vsig(hw, blk, i, id)) {
4630*71d10453SEric Joyner 				status = ice_rem_prof_id_vsig(hw, blk, i, id,
4631*71d10453SEric Joyner 							      &chg);
4632*71d10453SEric Joyner 				if (status)
4633*71d10453SEric Joyner 					goto err_ice_rem_flow_all;
4634*71d10453SEric Joyner 			}
4635*71d10453SEric Joyner 		}
4636*71d10453SEric Joyner 	}
4637*71d10453SEric Joyner 
4638*71d10453SEric Joyner 	status = ice_upd_prof_hw(hw, blk, &chg);
4639*71d10453SEric Joyner 
4640*71d10453SEric Joyner err_ice_rem_flow_all:
4641*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) {
4642*71d10453SEric Joyner 		LIST_DEL(&del->list_entry);
4643*71d10453SEric Joyner 		ice_free(hw, del);
4644*71d10453SEric Joyner 	}
4645*71d10453SEric Joyner 
4646*71d10453SEric Joyner 	return status;
4647*71d10453SEric Joyner }
4648*71d10453SEric Joyner 
4649*71d10453SEric Joyner /**
4650*71d10453SEric Joyner  * ice_rem_prof - remove profile
4651*71d10453SEric Joyner  * @hw: pointer to the HW struct
4652*71d10453SEric Joyner  * @blk: hardware block
4653*71d10453SEric Joyner  * @id: profile tracking ID
4654*71d10453SEric Joyner  *
4655*71d10453SEric Joyner  * This will remove the profile specified by the ID parameter, which was
4656*71d10453SEric Joyner  * previously created through ice_add_prof. If any existing entries
4657*71d10453SEric Joyner  * are associated with this profile, they will be removed as well.
4658*71d10453SEric Joyner  */
4659*71d10453SEric Joyner enum ice_status ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id)
4660*71d10453SEric Joyner {
4661*71d10453SEric Joyner 	struct ice_prof_map *pmap;
4662*71d10453SEric Joyner 	enum ice_status status;
4663*71d10453SEric Joyner 
4664*71d10453SEric Joyner 	ice_acquire_lock(&hw->blk[blk].es.prof_map_lock);
4665*71d10453SEric Joyner 
4666*71d10453SEric Joyner 	pmap = ice_search_prof_id_low(hw, blk, id);
4667*71d10453SEric Joyner 	if (!pmap) {
4668*71d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
4669*71d10453SEric Joyner 		goto err_ice_rem_prof;
4670*71d10453SEric Joyner 	}
4671*71d10453SEric Joyner 
4672*71d10453SEric Joyner 	/* remove all flows with this profile */
4673*71d10453SEric Joyner 	status = ice_rem_flow_all(hw, blk, pmap->profile_cookie);
4674*71d10453SEric Joyner 	if (status)
4675*71d10453SEric Joyner 		goto err_ice_rem_prof;
4676*71d10453SEric Joyner 
4677*71d10453SEric Joyner 	/* dereference profile, and possibly remove */
4678*71d10453SEric Joyner 	ice_prof_dec_ref(hw, blk, pmap->prof_id);
4679*71d10453SEric Joyner 
4680*71d10453SEric Joyner 	LIST_DEL(&pmap->list);
4681*71d10453SEric Joyner 	ice_free(hw, pmap);
4682*71d10453SEric Joyner 
4683*71d10453SEric Joyner err_ice_rem_prof:
4684*71d10453SEric Joyner 	ice_release_lock(&hw->blk[blk].es.prof_map_lock);
4685*71d10453SEric Joyner 	return status;
4686*71d10453SEric Joyner }
4687*71d10453SEric Joyner 
4688*71d10453SEric Joyner /**
4689*71d10453SEric Joyner  * ice_get_prof - get profile
4690*71d10453SEric Joyner  * @hw: pointer to the HW struct
4691*71d10453SEric Joyner  * @blk: hardware block
4692*71d10453SEric Joyner  * @hdl: profile handle
4693*71d10453SEric Joyner  * @chg: change list
4694*71d10453SEric Joyner  */
4695*71d10453SEric Joyner static enum ice_status
4696*71d10453SEric Joyner ice_get_prof(struct ice_hw *hw, enum ice_block blk, u64 hdl,
4697*71d10453SEric Joyner 	     struct LIST_HEAD_TYPE *chg)
4698*71d10453SEric Joyner {
4699*71d10453SEric Joyner 	struct ice_prof_map *map;
4700*71d10453SEric Joyner 	struct ice_chs_chg *p;
4701*71d10453SEric Joyner 	u16 i;
4702*71d10453SEric Joyner 
4703*71d10453SEric Joyner 	/* Get the details on the profile specified by the handle ID */
4704*71d10453SEric Joyner 	map = ice_search_prof_id(hw, blk, hdl);
4705*71d10453SEric Joyner 	if (!map)
4706*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
4707*71d10453SEric Joyner 
4708*71d10453SEric Joyner 	for (i = 0; i < map->ptg_cnt; i++) {
4709*71d10453SEric Joyner 		if (!hw->blk[blk].es.written[map->prof_id]) {
4710*71d10453SEric Joyner 			/* add ES to change list */
4711*71d10453SEric Joyner 			p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
4712*71d10453SEric Joyner 			if (!p)
4713*71d10453SEric Joyner 				goto err_ice_get_prof;
4714*71d10453SEric Joyner 
4715*71d10453SEric Joyner 			p->type = ICE_PTG_ES_ADD;
4716*71d10453SEric Joyner 			p->ptype = 0;
4717*71d10453SEric Joyner 			p->ptg = map->ptg[i];
4718*71d10453SEric Joyner 			p->add_ptg = 0;
4719*71d10453SEric Joyner 
4720*71d10453SEric Joyner 			p->add_prof = 1;
4721*71d10453SEric Joyner 			p->prof_id = map->prof_id;
4722*71d10453SEric Joyner 
4723*71d10453SEric Joyner 			hw->blk[blk].es.written[map->prof_id] = true;
4724*71d10453SEric Joyner 
4725*71d10453SEric Joyner 			LIST_ADD(&p->list_entry, chg);
4726*71d10453SEric Joyner 		}
4727*71d10453SEric Joyner 	}
4728*71d10453SEric Joyner 
4729*71d10453SEric Joyner 	return ICE_SUCCESS;
4730*71d10453SEric Joyner 
4731*71d10453SEric Joyner err_ice_get_prof:
4732*71d10453SEric Joyner 	/* let caller clean up the change list */
4733*71d10453SEric Joyner 	return ICE_ERR_NO_MEMORY;
4734*71d10453SEric Joyner }
4735*71d10453SEric Joyner 
4736*71d10453SEric Joyner /**
4737*71d10453SEric Joyner  * ice_get_profs_vsig - get a copy of the list of profiles from a VSIG
4738*71d10453SEric Joyner  * @hw: pointer to the HW struct
4739*71d10453SEric Joyner  * @blk: hardware block
4740*71d10453SEric Joyner  * @vsig: VSIG from which to copy the list
4741*71d10453SEric Joyner  * @lst: output list
4742*71d10453SEric Joyner  *
4743*71d10453SEric Joyner  * This routine makes a copy of the list of profiles in the specified VSIG.
4744*71d10453SEric Joyner  */
4745*71d10453SEric Joyner static enum ice_status
4746*71d10453SEric Joyner ice_get_profs_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,
4747*71d10453SEric Joyner 		   struct LIST_HEAD_TYPE *lst)
4748*71d10453SEric Joyner {
4749*71d10453SEric Joyner 	struct ice_vsig_prof *ent1, *ent2;
4750*71d10453SEric Joyner 	u16 idx = vsig & ICE_VSIG_IDX_M;
4751*71d10453SEric Joyner 
4752*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(ent1, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
4753*71d10453SEric Joyner 			    ice_vsig_prof, list) {
4754*71d10453SEric Joyner 		struct ice_vsig_prof *p;
4755*71d10453SEric Joyner 
4756*71d10453SEric Joyner 		/* copy to the input list */
4757*71d10453SEric Joyner 		p = (struct ice_vsig_prof *)ice_memdup(hw, ent1, sizeof(*p),
4758*71d10453SEric Joyner 						       ICE_NONDMA_TO_NONDMA);
4759*71d10453SEric Joyner 		if (!p)
4760*71d10453SEric Joyner 			goto err_ice_get_profs_vsig;
4761*71d10453SEric Joyner 
4762*71d10453SEric Joyner 		LIST_ADD_TAIL(&p->list, lst);
4763*71d10453SEric Joyner 	}
4764*71d10453SEric Joyner 
4765*71d10453SEric Joyner 	return ICE_SUCCESS;
4766*71d10453SEric Joyner 
4767*71d10453SEric Joyner err_ice_get_profs_vsig:
4768*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(ent1, ent2, lst, ice_vsig_prof, list) {
4769*71d10453SEric Joyner 		LIST_DEL(&ent1->list);
4770*71d10453SEric Joyner 		ice_free(hw, ent1);
4771*71d10453SEric Joyner 	}
4772*71d10453SEric Joyner 
4773*71d10453SEric Joyner 	return ICE_ERR_NO_MEMORY;
4774*71d10453SEric Joyner }
4775*71d10453SEric Joyner 
4776*71d10453SEric Joyner /**
4777*71d10453SEric Joyner  * ice_add_prof_to_lst - add profile entry to a list
4778*71d10453SEric Joyner  * @hw: pointer to the HW struct
4779*71d10453SEric Joyner  * @blk: hardware block
4780*71d10453SEric Joyner  * @lst: the list to be added to
4781*71d10453SEric Joyner  * @hdl: profile handle of entry to add
4782*71d10453SEric Joyner  */
4783*71d10453SEric Joyner static enum ice_status
4784*71d10453SEric Joyner ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk,
4785*71d10453SEric Joyner 		    struct LIST_HEAD_TYPE *lst, u64 hdl)
4786*71d10453SEric Joyner {
4787*71d10453SEric Joyner 	struct ice_prof_map *map;
4788*71d10453SEric Joyner 	struct ice_vsig_prof *p;
4789*71d10453SEric Joyner 	u16 i;
4790*71d10453SEric Joyner 
4791*71d10453SEric Joyner 	map = ice_search_prof_id(hw, blk, hdl);
4792*71d10453SEric Joyner 	if (!map)
4793*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
4794*71d10453SEric Joyner 
4795*71d10453SEric Joyner 	p = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*p));
4796*71d10453SEric Joyner 	if (!p)
4797*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
4798*71d10453SEric Joyner 
4799*71d10453SEric Joyner 	p->profile_cookie = map->profile_cookie;
4800*71d10453SEric Joyner 	p->prof_id = map->prof_id;
4801*71d10453SEric Joyner 	p->tcam_count = map->ptg_cnt;
4802*71d10453SEric Joyner 
4803*71d10453SEric Joyner 	for (i = 0; i < map->ptg_cnt; i++) {
4804*71d10453SEric Joyner 		p->tcam[i].prof_id = map->prof_id;
4805*71d10453SEric Joyner 		p->tcam[i].tcam_idx = ICE_INVALID_TCAM;
4806*71d10453SEric Joyner 		p->tcam[i].ptg = map->ptg[i];
4807*71d10453SEric Joyner 	}
4808*71d10453SEric Joyner 
4809*71d10453SEric Joyner 	LIST_ADD(&p->list, lst);
4810*71d10453SEric Joyner 
4811*71d10453SEric Joyner 	return ICE_SUCCESS;
4812*71d10453SEric Joyner }
4813*71d10453SEric Joyner 
4814*71d10453SEric Joyner /**
4815*71d10453SEric Joyner  * ice_move_vsi - move VSI to another VSIG
4816*71d10453SEric Joyner  * @hw: pointer to the HW struct
4817*71d10453SEric Joyner  * @blk: hardware block
4818*71d10453SEric Joyner  * @vsi: the VSI to move
4819*71d10453SEric Joyner  * @vsig: the VSIG to move the VSI to
4820*71d10453SEric Joyner  * @chg: the change list
4821*71d10453SEric Joyner  */
4822*71d10453SEric Joyner static enum ice_status
4823*71d10453SEric Joyner ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig,
4824*71d10453SEric Joyner 	     struct LIST_HEAD_TYPE *chg)
4825*71d10453SEric Joyner {
4826*71d10453SEric Joyner 	enum ice_status status;
4827*71d10453SEric Joyner 	struct ice_chs_chg *p;
4828*71d10453SEric Joyner 	u16 orig_vsig;
4829*71d10453SEric Joyner 
4830*71d10453SEric Joyner 	p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
4831*71d10453SEric Joyner 	if (!p)
4832*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
4833*71d10453SEric Joyner 
4834*71d10453SEric Joyner 	status = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig);
4835*71d10453SEric Joyner 	if (!status)
4836*71d10453SEric Joyner 		status = ice_vsig_add_mv_vsi(hw, blk, vsi, vsig);
4837*71d10453SEric Joyner 
4838*71d10453SEric Joyner 	if (status) {
4839*71d10453SEric Joyner 		ice_free(hw, p);
4840*71d10453SEric Joyner 		return status;
4841*71d10453SEric Joyner 	}
4842*71d10453SEric Joyner 
4843*71d10453SEric Joyner 	p->type = ICE_VSI_MOVE;
4844*71d10453SEric Joyner 	p->vsi = vsi;
4845*71d10453SEric Joyner 	p->orig_vsig = orig_vsig;
4846*71d10453SEric Joyner 	p->vsig = vsig;
4847*71d10453SEric Joyner 
4848*71d10453SEric Joyner 	LIST_ADD(&p->list_entry, chg);
4849*71d10453SEric Joyner 
4850*71d10453SEric Joyner 	return ICE_SUCCESS;
4851*71d10453SEric Joyner }
4852*71d10453SEric Joyner 
4853*71d10453SEric Joyner /**
4854*71d10453SEric Joyner  * ice_rem_chg_tcam_ent - remove a specific TCAM entry from change list
4855*71d10453SEric Joyner  * @hw: pointer to the HW struct
4856*71d10453SEric Joyner  * @idx: the index of the TCAM entry to remove
4857*71d10453SEric Joyner  * @chg: the list of change structures to search
4858*71d10453SEric Joyner  */
4859*71d10453SEric Joyner static void
4860*71d10453SEric Joyner ice_rem_chg_tcam_ent(struct ice_hw *hw, u16 idx, struct LIST_HEAD_TYPE *chg)
4861*71d10453SEric Joyner {
4862*71d10453SEric Joyner 	struct ice_chs_chg *pos, *tmp;
4863*71d10453SEric Joyner 
4864*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(tmp, pos, chg, ice_chs_chg, list_entry) {
4865*71d10453SEric Joyner 		if (tmp->type == ICE_TCAM_ADD && tmp->tcam_idx == idx) {
4866*71d10453SEric Joyner 			LIST_DEL(&tmp->list_entry);
4867*71d10453SEric Joyner 			ice_free(hw, tmp);
4868*71d10453SEric Joyner 		}
4869*71d10453SEric Joyner 	}
4870*71d10453SEric Joyner }
4871*71d10453SEric Joyner 
4872*71d10453SEric Joyner /**
4873*71d10453SEric Joyner  * ice_prof_tcam_ena_dis - add enable or disable TCAM change
4874*71d10453SEric Joyner  * @hw: pointer to the HW struct
4875*71d10453SEric Joyner  * @blk: hardware block
4876*71d10453SEric Joyner  * @enable: true to enable, false to disable
4877*71d10453SEric Joyner  * @vsig: the VSIG of the TCAM entry
4878*71d10453SEric Joyner  * @tcam: pointer the TCAM info structure of the TCAM to disable
4879*71d10453SEric Joyner  * @chg: the change list
4880*71d10453SEric Joyner  *
4881*71d10453SEric Joyner  * This function appends an enable or disable TCAM entry in the change log
4882*71d10453SEric Joyner  */
4883*71d10453SEric Joyner static enum ice_status
4884*71d10453SEric Joyner ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable,
4885*71d10453SEric Joyner 		      u16 vsig, struct ice_tcam_inf *tcam,
4886*71d10453SEric Joyner 		      struct LIST_HEAD_TYPE *chg)
4887*71d10453SEric Joyner {
4888*71d10453SEric Joyner 	enum ice_status status;
4889*71d10453SEric Joyner 	struct ice_chs_chg *p;
4890*71d10453SEric Joyner 
4891*71d10453SEric Joyner 	u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4892*71d10453SEric Joyner 	u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 };
4893*71d10453SEric Joyner 	u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
4894*71d10453SEric Joyner 
4895*71d10453SEric Joyner 	/* if disabling, free the TCAM */
4896*71d10453SEric Joyner 	if (!enable) {
4897*71d10453SEric Joyner 		status = ice_rel_tcam_idx(hw, blk, tcam->tcam_idx);
4898*71d10453SEric Joyner 
4899*71d10453SEric Joyner 		/* if we have already created a change for this TCAM entry, then
4900*71d10453SEric Joyner 		 * we need to remove that entry, in order to prevent writing to
4901*71d10453SEric Joyner 		 * a TCAM entry we no longer will have ownership of.
4902*71d10453SEric Joyner 		 */
4903*71d10453SEric Joyner 		ice_rem_chg_tcam_ent(hw, tcam->tcam_idx, chg);
4904*71d10453SEric Joyner 		tcam->tcam_idx = 0;
4905*71d10453SEric Joyner 		tcam->in_use = 0;
4906*71d10453SEric Joyner 		return status;
4907*71d10453SEric Joyner 	}
4908*71d10453SEric Joyner 
4909*71d10453SEric Joyner 	/* for re-enabling, reallocate a TCAM */
4910*71d10453SEric Joyner 	status = ice_alloc_tcam_ent(hw, blk, &tcam->tcam_idx);
4911*71d10453SEric Joyner 	if (status)
4912*71d10453SEric Joyner 		return status;
4913*71d10453SEric Joyner 
4914*71d10453SEric Joyner 	/* add TCAM to change list */
4915*71d10453SEric Joyner 	p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
4916*71d10453SEric Joyner 	if (!p)
4917*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
4918*71d10453SEric Joyner 
4919*71d10453SEric Joyner 	status = ice_tcam_write_entry(hw, blk, tcam->tcam_idx, tcam->prof_id,
4920*71d10453SEric Joyner 				      tcam->ptg, vsig, 0, 0, vl_msk, dc_msk,
4921*71d10453SEric Joyner 				      nm_msk);
4922*71d10453SEric Joyner 	if (status)
4923*71d10453SEric Joyner 		goto err_ice_prof_tcam_ena_dis;
4924*71d10453SEric Joyner 
4925*71d10453SEric Joyner 	tcam->in_use = 1;
4926*71d10453SEric Joyner 
4927*71d10453SEric Joyner 	p->type = ICE_TCAM_ADD;
4928*71d10453SEric Joyner 	p->add_tcam_idx = true;
4929*71d10453SEric Joyner 	p->prof_id = tcam->prof_id;
4930*71d10453SEric Joyner 	p->ptg = tcam->ptg;
4931*71d10453SEric Joyner 	p->vsig = 0;
4932*71d10453SEric Joyner 	p->tcam_idx = tcam->tcam_idx;
4933*71d10453SEric Joyner 
4934*71d10453SEric Joyner 	/* log change */
4935*71d10453SEric Joyner 	LIST_ADD(&p->list_entry, chg);
4936*71d10453SEric Joyner 
4937*71d10453SEric Joyner 	return ICE_SUCCESS;
4938*71d10453SEric Joyner 
4939*71d10453SEric Joyner err_ice_prof_tcam_ena_dis:
4940*71d10453SEric Joyner 	ice_free(hw, p);
4941*71d10453SEric Joyner 	return status;
4942*71d10453SEric Joyner }
4943*71d10453SEric Joyner 
4944*71d10453SEric Joyner /**
4945*71d10453SEric Joyner  * ice_adj_prof_priorities - adjust profile based on priorities
4946*71d10453SEric Joyner  * @hw: pointer to the HW struct
4947*71d10453SEric Joyner  * @blk: hardware block
4948*71d10453SEric Joyner  * @vsig: the VSIG for which to adjust profile priorities
4949*71d10453SEric Joyner  * @chg: the change list
4950*71d10453SEric Joyner  */
4951*71d10453SEric Joyner static enum ice_status
4952*71d10453SEric Joyner ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
4953*71d10453SEric Joyner 			struct LIST_HEAD_TYPE *chg)
4954*71d10453SEric Joyner {
4955*71d10453SEric Joyner 	ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
4956*71d10453SEric Joyner 	enum ice_status status = ICE_SUCCESS;
4957*71d10453SEric Joyner 	struct ice_vsig_prof *t;
4958*71d10453SEric Joyner 	u16 idx;
4959*71d10453SEric Joyner 
4960*71d10453SEric Joyner 	ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
4961*71d10453SEric Joyner 	idx = vsig & ICE_VSIG_IDX_M;
4962*71d10453SEric Joyner 
4963*71d10453SEric Joyner 	/* Priority is based on the order in which the profiles are added. The
4964*71d10453SEric Joyner 	 * newest added profile has highest priority and the oldest added
4965*71d10453SEric Joyner 	 * profile has the lowest priority. Since the profile property list for
4966*71d10453SEric Joyner 	 * a VSIG is sorted from newest to oldest, this code traverses the list
4967*71d10453SEric Joyner 	 * in order and enables the first of each PTG that it finds (that is not
4968*71d10453SEric Joyner 	 * already enabled); it also disables any duplicate PTGs that it finds
4969*71d10453SEric Joyner 	 * in the older profiles (that are currently enabled).
4970*71d10453SEric Joyner 	 */
4971*71d10453SEric Joyner 
4972*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(t, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
4973*71d10453SEric Joyner 			    ice_vsig_prof, list) {
4974*71d10453SEric Joyner 		u16 i;
4975*71d10453SEric Joyner 
4976*71d10453SEric Joyner 		for (i = 0; i < t->tcam_count; i++) {
4977*71d10453SEric Joyner 			bool used;
4978*71d10453SEric Joyner 
4979*71d10453SEric Joyner 			/* Scan the priorities from newest to oldest.
4980*71d10453SEric Joyner 			 * Make sure that the newest profiles take priority.
4981*71d10453SEric Joyner 			 */
4982*71d10453SEric Joyner 			used = ice_is_bit_set(ptgs_used, t->tcam[i].ptg);
4983*71d10453SEric Joyner 
4984*71d10453SEric Joyner 			if (used && t->tcam[i].in_use) {
4985*71d10453SEric Joyner 				/* need to mark this PTG as never match, as it
4986*71d10453SEric Joyner 				 * was already in use and therefore duplicate
4987*71d10453SEric Joyner 				 * (and lower priority)
4988*71d10453SEric Joyner 				 */
4989*71d10453SEric Joyner 				status = ice_prof_tcam_ena_dis(hw, blk, false,
4990*71d10453SEric Joyner 							       vsig,
4991*71d10453SEric Joyner 							       &t->tcam[i],
4992*71d10453SEric Joyner 							       chg);
4993*71d10453SEric Joyner 				if (status)
4994*71d10453SEric Joyner 					return status;
4995*71d10453SEric Joyner 			} else if (!used && !t->tcam[i].in_use) {
4996*71d10453SEric Joyner 				/* need to enable this PTG, as it in not in use
4997*71d10453SEric Joyner 				 * and not enabled (highest priority)
4998*71d10453SEric Joyner 				 */
4999*71d10453SEric Joyner 				status = ice_prof_tcam_ena_dis(hw, blk, true,
5000*71d10453SEric Joyner 							       vsig,
5001*71d10453SEric Joyner 							       &t->tcam[i],
5002*71d10453SEric Joyner 							       chg);
5003*71d10453SEric Joyner 				if (status)
5004*71d10453SEric Joyner 					return status;
5005*71d10453SEric Joyner 			}
5006*71d10453SEric Joyner 
5007*71d10453SEric Joyner 			/* keep track of used ptgs */
5008*71d10453SEric Joyner 			ice_set_bit(t->tcam[i].ptg, ptgs_used);
5009*71d10453SEric Joyner 		}
5010*71d10453SEric Joyner 	}
5011*71d10453SEric Joyner 
5012*71d10453SEric Joyner 	return status;
5013*71d10453SEric Joyner }
5014*71d10453SEric Joyner 
5015*71d10453SEric Joyner /**
5016*71d10453SEric Joyner  * ice_add_prof_id_vsig - add profile to VSIG
5017*71d10453SEric Joyner  * @hw: pointer to the HW struct
5018*71d10453SEric Joyner  * @blk: hardware block
5019*71d10453SEric Joyner  * @vsig: the VSIG to which this profile is to be added
5020*71d10453SEric Joyner  * @hdl: the profile handle indicating the profile to add
5021*71d10453SEric Joyner  * @rev: true to add entries to the end of the list
5022*71d10453SEric Joyner  * @chg: the change list
5023*71d10453SEric Joyner  */
5024*71d10453SEric Joyner static enum ice_status
5025*71d10453SEric Joyner ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
5026*71d10453SEric Joyner 		     bool rev, struct LIST_HEAD_TYPE *chg)
5027*71d10453SEric Joyner {
5028*71d10453SEric Joyner 	/* Masks that ignore flags */
5029*71d10453SEric Joyner 	u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5030*71d10453SEric Joyner 	u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 };
5031*71d10453SEric Joyner 	u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
5032*71d10453SEric Joyner 	struct ice_prof_map *map;
5033*71d10453SEric Joyner 	struct ice_vsig_prof *t;
5034*71d10453SEric Joyner 	struct ice_chs_chg *p;
5035*71d10453SEric Joyner 	u16 vsig_idx, i;
5036*71d10453SEric Joyner 
5037*71d10453SEric Joyner 	/* Get the details on the profile specified by the handle ID */
5038*71d10453SEric Joyner 	map = ice_search_prof_id(hw, blk, hdl);
5039*71d10453SEric Joyner 	if (!map)
5040*71d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
5041*71d10453SEric Joyner 
5042*71d10453SEric Joyner 	/* Error, if this VSIG already has this profile */
5043*71d10453SEric Joyner 	if (ice_has_prof_vsig(hw, blk, vsig, hdl))
5044*71d10453SEric Joyner 		return ICE_ERR_ALREADY_EXISTS;
5045*71d10453SEric Joyner 
5046*71d10453SEric Joyner 	/* new VSIG profile structure */
5047*71d10453SEric Joyner 	t = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*t));
5048*71d10453SEric Joyner 	if (!t)
5049*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
5050*71d10453SEric Joyner 
5051*71d10453SEric Joyner 	t->profile_cookie = map->profile_cookie;
5052*71d10453SEric Joyner 	t->prof_id = map->prof_id;
5053*71d10453SEric Joyner 	t->tcam_count = map->ptg_cnt;
5054*71d10453SEric Joyner 
5055*71d10453SEric Joyner 	/* create TCAM entries */
5056*71d10453SEric Joyner 	for (i = 0; i < map->ptg_cnt; i++) {
5057*71d10453SEric Joyner 		enum ice_status status;
5058*71d10453SEric Joyner 		u16 tcam_idx;
5059*71d10453SEric Joyner 
5060*71d10453SEric Joyner 		/* add TCAM to change list */
5061*71d10453SEric Joyner 		p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
5062*71d10453SEric Joyner 		if (!p)
5063*71d10453SEric Joyner 			goto err_ice_add_prof_id_vsig;
5064*71d10453SEric Joyner 
5065*71d10453SEric Joyner 		/* allocate the TCAM entry index */
5066*71d10453SEric Joyner 		status = ice_alloc_tcam_ent(hw, blk, &tcam_idx);
5067*71d10453SEric Joyner 		if (status) {
5068*71d10453SEric Joyner 			ice_free(hw, p);
5069*71d10453SEric Joyner 			goto err_ice_add_prof_id_vsig;
5070*71d10453SEric Joyner 		}
5071*71d10453SEric Joyner 
5072*71d10453SEric Joyner 		t->tcam[i].ptg = map->ptg[i];
5073*71d10453SEric Joyner 		t->tcam[i].prof_id = map->prof_id;
5074*71d10453SEric Joyner 		t->tcam[i].tcam_idx = tcam_idx;
5075*71d10453SEric Joyner 		t->tcam[i].in_use = true;
5076*71d10453SEric Joyner 
5077*71d10453SEric Joyner 		p->type = ICE_TCAM_ADD;
5078*71d10453SEric Joyner 		p->add_tcam_idx = true;
5079*71d10453SEric Joyner 		p->prof_id = t->tcam[i].prof_id;
5080*71d10453SEric Joyner 		p->ptg = t->tcam[i].ptg;
5081*71d10453SEric Joyner 		p->vsig = vsig;
5082*71d10453SEric Joyner 		p->tcam_idx = t->tcam[i].tcam_idx;
5083*71d10453SEric Joyner 
5084*71d10453SEric Joyner 		/* write the TCAM entry */
5085*71d10453SEric Joyner 		status = ice_tcam_write_entry(hw, blk, t->tcam[i].tcam_idx,
5086*71d10453SEric Joyner 					      t->tcam[i].prof_id,
5087*71d10453SEric Joyner 					      t->tcam[i].ptg, vsig, 0, 0,
5088*71d10453SEric Joyner 					      vl_msk, dc_msk, nm_msk);
5089*71d10453SEric Joyner 		if (status) {
5090*71d10453SEric Joyner 			ice_free(hw, p);
5091*71d10453SEric Joyner 			goto err_ice_add_prof_id_vsig;
5092*71d10453SEric Joyner 		}
5093*71d10453SEric Joyner 
5094*71d10453SEric Joyner 		/* log change */
5095*71d10453SEric Joyner 		LIST_ADD(&p->list_entry, chg);
5096*71d10453SEric Joyner 	}
5097*71d10453SEric Joyner 
5098*71d10453SEric Joyner 	/* add profile to VSIG */
5099*71d10453SEric Joyner 	vsig_idx = vsig & ICE_VSIG_IDX_M;
5100*71d10453SEric Joyner 	if (rev)
5101*71d10453SEric Joyner 		LIST_ADD_TAIL(&t->list,
5102*71d10453SEric Joyner 			      &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst);
5103*71d10453SEric Joyner 	else
5104*71d10453SEric Joyner 		LIST_ADD(&t->list,
5105*71d10453SEric Joyner 			 &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst);
5106*71d10453SEric Joyner 
5107*71d10453SEric Joyner 	return ICE_SUCCESS;
5108*71d10453SEric Joyner 
5109*71d10453SEric Joyner err_ice_add_prof_id_vsig:
5110*71d10453SEric Joyner 	/* let caller clean up the change list */
5111*71d10453SEric Joyner 	ice_free(hw, t);
5112*71d10453SEric Joyner 	return ICE_ERR_NO_MEMORY;
5113*71d10453SEric Joyner }
5114*71d10453SEric Joyner 
5115*71d10453SEric Joyner /**
5116*71d10453SEric Joyner  * ice_create_prof_id_vsig - add a new VSIG with a single profile
5117*71d10453SEric Joyner  * @hw: pointer to the HW struct
5118*71d10453SEric Joyner  * @blk: hardware block
5119*71d10453SEric Joyner  * @vsi: the initial VSI that will be in VSIG
5120*71d10453SEric Joyner  * @hdl: the profile handle of the profile that will be added to the VSIG
5121*71d10453SEric Joyner  * @chg: the change list
5122*71d10453SEric Joyner  */
5123*71d10453SEric Joyner static enum ice_status
5124*71d10453SEric Joyner ice_create_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl,
5125*71d10453SEric Joyner 			struct LIST_HEAD_TYPE *chg)
5126*71d10453SEric Joyner {
5127*71d10453SEric Joyner 	enum ice_status status;
5128*71d10453SEric Joyner 	struct ice_chs_chg *p;
5129*71d10453SEric Joyner 	u16 new_vsig;
5130*71d10453SEric Joyner 
5131*71d10453SEric Joyner 	p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
5132*71d10453SEric Joyner 	if (!p)
5133*71d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
5134*71d10453SEric Joyner 
5135*71d10453SEric Joyner 	new_vsig = ice_vsig_alloc(hw, blk);
5136*71d10453SEric Joyner 	if (!new_vsig) {
5137*71d10453SEric Joyner 		status = ICE_ERR_HW_TABLE;
5138*71d10453SEric Joyner 		goto err_ice_create_prof_id_vsig;
5139*71d10453SEric Joyner 	}
5140*71d10453SEric Joyner 
5141*71d10453SEric Joyner 	status = ice_move_vsi(hw, blk, vsi, new_vsig, chg);
5142*71d10453SEric Joyner 	if (status)
5143*71d10453SEric Joyner 		goto err_ice_create_prof_id_vsig;
5144*71d10453SEric Joyner 
5145*71d10453SEric Joyner 	status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, false, chg);
5146*71d10453SEric Joyner 	if (status)
5147*71d10453SEric Joyner 		goto err_ice_create_prof_id_vsig;
5148*71d10453SEric Joyner 
5149*71d10453SEric Joyner 	p->type = ICE_VSIG_ADD;
5150*71d10453SEric Joyner 	p->vsi = vsi;
5151*71d10453SEric Joyner 	p->orig_vsig = ICE_DEFAULT_VSIG;
5152*71d10453SEric Joyner 	p->vsig = new_vsig;
5153*71d10453SEric Joyner 
5154*71d10453SEric Joyner 	LIST_ADD(&p->list_entry, chg);
5155*71d10453SEric Joyner 
5156*71d10453SEric Joyner 	return ICE_SUCCESS;
5157*71d10453SEric Joyner 
5158*71d10453SEric Joyner err_ice_create_prof_id_vsig:
5159*71d10453SEric Joyner 	/* let caller clean up the change list */
5160*71d10453SEric Joyner 	ice_free(hw, p);
5161*71d10453SEric Joyner 	return status;
5162*71d10453SEric Joyner }
5163*71d10453SEric Joyner 
5164*71d10453SEric Joyner /**
5165*71d10453SEric Joyner  * ice_create_vsig_from_lst - create a new VSIG with a list of profiles
5166*71d10453SEric Joyner  * @hw: pointer to the HW struct
5167*71d10453SEric Joyner  * @blk: hardware block
5168*71d10453SEric Joyner  * @vsi: the initial VSI that will be in VSIG
5169*71d10453SEric Joyner  * @lst: the list of profile that will be added to the VSIG
5170*71d10453SEric Joyner  * @new_vsig: return of new VSIG
5171*71d10453SEric Joyner  * @chg: the change list
5172*71d10453SEric Joyner  */
5173*71d10453SEric Joyner static enum ice_status
5174*71d10453SEric Joyner ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi,
5175*71d10453SEric Joyner 			 struct LIST_HEAD_TYPE *lst, u16 *new_vsig,
5176*71d10453SEric Joyner 			 struct LIST_HEAD_TYPE *chg)
5177*71d10453SEric Joyner {
5178*71d10453SEric Joyner 	struct ice_vsig_prof *t;
5179*71d10453SEric Joyner 	enum ice_status status;
5180*71d10453SEric Joyner 	u16 vsig;
5181*71d10453SEric Joyner 
5182*71d10453SEric Joyner 	vsig = ice_vsig_alloc(hw, blk);
5183*71d10453SEric Joyner 	if (!vsig)
5184*71d10453SEric Joyner 		return ICE_ERR_HW_TABLE;
5185*71d10453SEric Joyner 
5186*71d10453SEric Joyner 	status = ice_move_vsi(hw, blk, vsi, vsig, chg);
5187*71d10453SEric Joyner 	if (status)
5188*71d10453SEric Joyner 		return status;
5189*71d10453SEric Joyner 
5190*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(t, lst, ice_vsig_prof, list) {
5191*71d10453SEric Joyner 		/* Reverse the order here since we are copying the list */
5192*71d10453SEric Joyner 		status = ice_add_prof_id_vsig(hw, blk, vsig, t->profile_cookie,
5193*71d10453SEric Joyner 					      true, chg);
5194*71d10453SEric Joyner 		if (status)
5195*71d10453SEric Joyner 			return status;
5196*71d10453SEric Joyner 	}
5197*71d10453SEric Joyner 
5198*71d10453SEric Joyner 	*new_vsig = vsig;
5199*71d10453SEric Joyner 
5200*71d10453SEric Joyner 	return ICE_SUCCESS;
5201*71d10453SEric Joyner }
5202*71d10453SEric Joyner 
5203*71d10453SEric Joyner /**
5204*71d10453SEric Joyner  * ice_find_prof_vsig - find a VSIG with a specific profile handle
5205*71d10453SEric Joyner  * @hw: pointer to the HW struct
5206*71d10453SEric Joyner  * @blk: hardware block
5207*71d10453SEric Joyner  * @hdl: the profile handle of the profile to search for
5208*71d10453SEric Joyner  * @vsig: returns the VSIG with the matching profile
5209*71d10453SEric Joyner  */
5210*71d10453SEric Joyner static bool
5211*71d10453SEric Joyner ice_find_prof_vsig(struct ice_hw *hw, enum ice_block blk, u64 hdl, u16 *vsig)
5212*71d10453SEric Joyner {
5213*71d10453SEric Joyner 	struct ice_vsig_prof *t;
5214*71d10453SEric Joyner 	struct LIST_HEAD_TYPE lst;
5215*71d10453SEric Joyner 	enum ice_status status;
5216*71d10453SEric Joyner 
5217*71d10453SEric Joyner 	INIT_LIST_HEAD(&lst);
5218*71d10453SEric Joyner 
5219*71d10453SEric Joyner 	t = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*t));
5220*71d10453SEric Joyner 	if (!t)
5221*71d10453SEric Joyner 		return false;
5222*71d10453SEric Joyner 
5223*71d10453SEric Joyner 	t->profile_cookie = hdl;
5224*71d10453SEric Joyner 	LIST_ADD(&t->list, &lst);
5225*71d10453SEric Joyner 
5226*71d10453SEric Joyner 	status = ice_find_dup_props_vsig(hw, blk, &lst, vsig);
5227*71d10453SEric Joyner 
5228*71d10453SEric Joyner 	LIST_DEL(&t->list);
5229*71d10453SEric Joyner 	ice_free(hw, t);
5230*71d10453SEric Joyner 
5231*71d10453SEric Joyner 	return status == ICE_SUCCESS;
5232*71d10453SEric Joyner }
5233*71d10453SEric Joyner 
5234*71d10453SEric Joyner /**
5235*71d10453SEric Joyner  * ice_add_vsi_flow - add VSI flow
5236*71d10453SEric Joyner  * @hw: pointer to the HW struct
5237*71d10453SEric Joyner  * @blk: hardware block
5238*71d10453SEric Joyner  * @vsi: input VSI
5239*71d10453SEric Joyner  * @vsig: target VSIG to include the input VSI
5240*71d10453SEric Joyner  *
5241*71d10453SEric Joyner  * Calling this function will add the VSI to a given VSIG and
5242*71d10453SEric Joyner  * update the HW tables accordingly. This call can be used to
5243*71d10453SEric Joyner  * add multiple VSIs to a VSIG if we know beforehand that those
5244*71d10453SEric Joyner  * VSIs have the same characteristics of the VSIG. This will
5245*71d10453SEric Joyner  * save time in generating a new VSIG and TCAMs till a match is
5246*71d10453SEric Joyner  * found and subsequent rollback when a matching VSIG is found.
5247*71d10453SEric Joyner  */
5248*71d10453SEric Joyner enum ice_status
5249*71d10453SEric Joyner ice_add_vsi_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
5250*71d10453SEric Joyner {
5251*71d10453SEric Joyner 	struct ice_chs_chg *tmp, *del;
5252*71d10453SEric Joyner 	struct LIST_HEAD_TYPE chg;
5253*71d10453SEric Joyner 	enum ice_status status;
5254*71d10453SEric Joyner 
5255*71d10453SEric Joyner 	/* if target VSIG is default the move is invalid */
5256*71d10453SEric Joyner 	if ((vsig & ICE_VSIG_IDX_M) == ICE_DEFAULT_VSIG)
5257*71d10453SEric Joyner 		return ICE_ERR_PARAM;
5258*71d10453SEric Joyner 
5259*71d10453SEric Joyner 	INIT_LIST_HEAD(&chg);
5260*71d10453SEric Joyner 
5261*71d10453SEric Joyner 	/* move VSI to the VSIG that matches */
5262*71d10453SEric Joyner 	status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
5263*71d10453SEric Joyner 	/* update hardware if success */
5264*71d10453SEric Joyner 	if (!status)
5265*71d10453SEric Joyner 		status = ice_upd_prof_hw(hw, blk, &chg);
5266*71d10453SEric Joyner 
5267*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) {
5268*71d10453SEric Joyner 		LIST_DEL(&del->list_entry);
5269*71d10453SEric Joyner 		ice_free(hw, del);
5270*71d10453SEric Joyner 	}
5271*71d10453SEric Joyner 
5272*71d10453SEric Joyner 	return status;
5273*71d10453SEric Joyner }
5274*71d10453SEric Joyner 
5275*71d10453SEric Joyner /**
5276*71d10453SEric Joyner  * ice_add_prof_id_flow - add profile flow
5277*71d10453SEric Joyner  * @hw: pointer to the HW struct
5278*71d10453SEric Joyner  * @blk: hardware block
5279*71d10453SEric Joyner  * @vsi: the VSI to enable with the profile specified by ID
5280*71d10453SEric Joyner  * @hdl: profile handle
5281*71d10453SEric Joyner  *
5282*71d10453SEric Joyner  * Calling this function will update the hardware tables to enable the
5283*71d10453SEric Joyner  * profile indicated by the ID parameter for the VSIs specified in the VSI
5284*71d10453SEric Joyner  * array. Once successfully called, the flow will be enabled.
5285*71d10453SEric Joyner  */
5286*71d10453SEric Joyner enum ice_status
5287*71d10453SEric Joyner ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
5288*71d10453SEric Joyner {
5289*71d10453SEric Joyner 	struct ice_vsig_prof *tmp1, *del1;
5290*71d10453SEric Joyner 	struct LIST_HEAD_TYPE union_lst;
5291*71d10453SEric Joyner 	struct ice_chs_chg *tmp, *del;
5292*71d10453SEric Joyner 	struct LIST_HEAD_TYPE chg;
5293*71d10453SEric Joyner 	enum ice_status status;
5294*71d10453SEric Joyner 	u16 vsig;
5295*71d10453SEric Joyner 
5296*71d10453SEric Joyner 	INIT_LIST_HEAD(&union_lst);
5297*71d10453SEric Joyner 	INIT_LIST_HEAD(&chg);
5298*71d10453SEric Joyner 
5299*71d10453SEric Joyner 	/* Get profile */
5300*71d10453SEric Joyner 	status = ice_get_prof(hw, blk, hdl, &chg);
5301*71d10453SEric Joyner 	if (status)
5302*71d10453SEric Joyner 		return status;
5303*71d10453SEric Joyner 
5304*71d10453SEric Joyner 	/* determine if VSI is already part of a VSIG */
5305*71d10453SEric Joyner 	status = ice_vsig_find_vsi(hw, blk, vsi, &vsig);
5306*71d10453SEric Joyner 	if (!status && vsig) {
5307*71d10453SEric Joyner 		bool only_vsi;
5308*71d10453SEric Joyner 		u16 or_vsig;
5309*71d10453SEric Joyner 		u16 ref;
5310*71d10453SEric Joyner 
5311*71d10453SEric Joyner 		/* found in VSIG */
5312*71d10453SEric Joyner 		or_vsig = vsig;
5313*71d10453SEric Joyner 
5314*71d10453SEric Joyner 		/* make sure that there is no overlap/conflict between the new
5315*71d10453SEric Joyner 		 * characteristics and the existing ones; we don't support that
5316*71d10453SEric Joyner 		 * scenario
5317*71d10453SEric Joyner 		 */
5318*71d10453SEric Joyner 		if (ice_has_prof_vsig(hw, blk, vsig, hdl)) {
5319*71d10453SEric Joyner 			status = ICE_ERR_ALREADY_EXISTS;
5320*71d10453SEric Joyner 			goto err_ice_add_prof_id_flow;
5321*71d10453SEric Joyner 		}
5322*71d10453SEric Joyner 
5323*71d10453SEric Joyner 		/* last VSI in the VSIG? */
5324*71d10453SEric Joyner 		status = ice_vsig_get_ref(hw, blk, vsig, &ref);
5325*71d10453SEric Joyner 		if (status)
5326*71d10453SEric Joyner 			goto err_ice_add_prof_id_flow;
5327*71d10453SEric Joyner 		only_vsi = (ref == 1);
5328*71d10453SEric Joyner 
5329*71d10453SEric Joyner 		/* create a union of the current profiles and the one being
5330*71d10453SEric Joyner 		 * added
5331*71d10453SEric Joyner 		 */
5332*71d10453SEric Joyner 		status = ice_get_profs_vsig(hw, blk, vsig, &union_lst);
5333*71d10453SEric Joyner 		if (status)
5334*71d10453SEric Joyner 			goto err_ice_add_prof_id_flow;
5335*71d10453SEric Joyner 
5336*71d10453SEric Joyner 		status = ice_add_prof_to_lst(hw, blk, &union_lst, hdl);
5337*71d10453SEric Joyner 		if (status)
5338*71d10453SEric Joyner 			goto err_ice_add_prof_id_flow;
5339*71d10453SEric Joyner 
5340*71d10453SEric Joyner 		/* search for an existing VSIG with an exact charc match */
5341*71d10453SEric Joyner 		status = ice_find_dup_props_vsig(hw, blk, &union_lst, &vsig);
5342*71d10453SEric Joyner 		if (!status) {
5343*71d10453SEric Joyner 			/* move VSI to the VSIG that matches */
5344*71d10453SEric Joyner 			status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
5345*71d10453SEric Joyner 			if (status)
5346*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5347*71d10453SEric Joyner 
5348*71d10453SEric Joyner 			/* VSI has been moved out of or_vsig. If the or_vsig had
5349*71d10453SEric Joyner 			 * only that VSI it is now empty and can be removed.
5350*71d10453SEric Joyner 			 */
5351*71d10453SEric Joyner 			if (only_vsi) {
5352*71d10453SEric Joyner 				status = ice_rem_vsig(hw, blk, or_vsig, &chg);
5353*71d10453SEric Joyner 				if (status)
5354*71d10453SEric Joyner 					goto err_ice_add_prof_id_flow;
5355*71d10453SEric Joyner 			}
5356*71d10453SEric Joyner 		} else if (only_vsi) {
5357*71d10453SEric Joyner 			/* If the original VSIG only contains one VSI, then it
5358*71d10453SEric Joyner 			 * will be the requesting VSI. In this case the VSI is
5359*71d10453SEric Joyner 			 * not sharing entries and we can simply add the new
5360*71d10453SEric Joyner 			 * profile to the VSIG.
5361*71d10453SEric Joyner 			 */
5362*71d10453SEric Joyner 			status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, false,
5363*71d10453SEric Joyner 						      &chg);
5364*71d10453SEric Joyner 			if (status)
5365*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5366*71d10453SEric Joyner 
5367*71d10453SEric Joyner 			/* Adjust priorities */
5368*71d10453SEric Joyner 			status = ice_adj_prof_priorities(hw, blk, vsig, &chg);
5369*71d10453SEric Joyner 			if (status)
5370*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5371*71d10453SEric Joyner 		} else {
5372*71d10453SEric Joyner 			/* No match, so we need a new VSIG */
5373*71d10453SEric Joyner 			status = ice_create_vsig_from_lst(hw, blk, vsi,
5374*71d10453SEric Joyner 							  &union_lst, &vsig,
5375*71d10453SEric Joyner 							  &chg);
5376*71d10453SEric Joyner 			if (status)
5377*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5378*71d10453SEric Joyner 
5379*71d10453SEric Joyner 			/* Adjust priorities */
5380*71d10453SEric Joyner 			status = ice_adj_prof_priorities(hw, blk, vsig, &chg);
5381*71d10453SEric Joyner 			if (status)
5382*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5383*71d10453SEric Joyner 		}
5384*71d10453SEric Joyner 	} else {
5385*71d10453SEric Joyner 		/* need to find or add a VSIG */
5386*71d10453SEric Joyner 		/* search for an existing VSIG with an exact charc match */
5387*71d10453SEric Joyner 		if (ice_find_prof_vsig(hw, blk, hdl, &vsig)) {
5388*71d10453SEric Joyner 			/* found an exact match */
5389*71d10453SEric Joyner 			/* add or move VSI to the VSIG that matches */
5390*71d10453SEric Joyner 			status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
5391*71d10453SEric Joyner 			if (status)
5392*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5393*71d10453SEric Joyner 		} else {
5394*71d10453SEric Joyner 			/* we did not find an exact match */
5395*71d10453SEric Joyner 			/* we need to add a VSIG */
5396*71d10453SEric Joyner 			status = ice_create_prof_id_vsig(hw, blk, vsi, hdl,
5397*71d10453SEric Joyner 							 &chg);
5398*71d10453SEric Joyner 			if (status)
5399*71d10453SEric Joyner 				goto err_ice_add_prof_id_flow;
5400*71d10453SEric Joyner 		}
5401*71d10453SEric Joyner 	}
5402*71d10453SEric Joyner 
5403*71d10453SEric Joyner 	/* update hardware */
5404*71d10453SEric Joyner 	if (!status)
5405*71d10453SEric Joyner 		status = ice_upd_prof_hw(hw, blk, &chg);
5406*71d10453SEric Joyner 
5407*71d10453SEric Joyner err_ice_add_prof_id_flow:
5408*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) {
5409*71d10453SEric Joyner 		LIST_DEL(&del->list_entry);
5410*71d10453SEric Joyner 		ice_free(hw, del);
5411*71d10453SEric Joyner 	}
5412*71d10453SEric Joyner 
5413*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del1, tmp1, &union_lst, ice_vsig_prof, list) {
5414*71d10453SEric Joyner 		LIST_DEL(&del1->list);
5415*71d10453SEric Joyner 		ice_free(hw, del1);
5416*71d10453SEric Joyner 	}
5417*71d10453SEric Joyner 
5418*71d10453SEric Joyner 	return status;
5419*71d10453SEric Joyner }
5420*71d10453SEric Joyner 
5421*71d10453SEric Joyner /**
5422*71d10453SEric Joyner  * ice_add_flow - add flow
5423*71d10453SEric Joyner  * @hw: pointer to the HW struct
5424*71d10453SEric Joyner  * @blk: hardware block
5425*71d10453SEric Joyner  * @vsi: array of VSIs to enable with the profile specified by ID
5426*71d10453SEric Joyner  * @count: number of elements in the VSI array
5427*71d10453SEric Joyner  * @id: profile tracking ID
5428*71d10453SEric Joyner  *
5429*71d10453SEric Joyner  * Calling this function will update the hardware tables to enable the
5430*71d10453SEric Joyner  * profile indicated by the ID parameter for the VSIs specified in the VSI
5431*71d10453SEric Joyner  * array. Once successfully called, the flow will be enabled.
5432*71d10453SEric Joyner  */
5433*71d10453SEric Joyner enum ice_status
5434*71d10453SEric Joyner ice_add_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count,
5435*71d10453SEric Joyner 	     u64 id)
5436*71d10453SEric Joyner {
5437*71d10453SEric Joyner 	enum ice_status status;
5438*71d10453SEric Joyner 	u16 i;
5439*71d10453SEric Joyner 
5440*71d10453SEric Joyner 	for (i = 0; i < count; i++) {
5441*71d10453SEric Joyner 		status = ice_add_prof_id_flow(hw, blk, vsi[i], id);
5442*71d10453SEric Joyner 		if (status)
5443*71d10453SEric Joyner 			return status;
5444*71d10453SEric Joyner 	}
5445*71d10453SEric Joyner 
5446*71d10453SEric Joyner 	return ICE_SUCCESS;
5447*71d10453SEric Joyner }
5448*71d10453SEric Joyner 
5449*71d10453SEric Joyner /**
5450*71d10453SEric Joyner  * ice_rem_prof_from_list - remove a profile from list
5451*71d10453SEric Joyner  * @hw: pointer to the HW struct
5452*71d10453SEric Joyner  * @lst: list to remove the profile from
5453*71d10453SEric Joyner  * @hdl: the profile handle indicating the profile to remove
5454*71d10453SEric Joyner  */
5455*71d10453SEric Joyner static enum ice_status
5456*71d10453SEric Joyner ice_rem_prof_from_list(struct ice_hw *hw, struct LIST_HEAD_TYPE *lst, u64 hdl)
5457*71d10453SEric Joyner {
5458*71d10453SEric Joyner 	struct ice_vsig_prof *ent, *tmp;
5459*71d10453SEric Joyner 
5460*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, lst, ice_vsig_prof, list) {
5461*71d10453SEric Joyner 		if (ent->profile_cookie == hdl) {
5462*71d10453SEric Joyner 			LIST_DEL(&ent->list);
5463*71d10453SEric Joyner 			ice_free(hw, ent);
5464*71d10453SEric Joyner 			return ICE_SUCCESS;
5465*71d10453SEric Joyner 		}
5466*71d10453SEric Joyner 	}
5467*71d10453SEric Joyner 
5468*71d10453SEric Joyner 	return ICE_ERR_DOES_NOT_EXIST;
5469*71d10453SEric Joyner }
5470*71d10453SEric Joyner 
5471*71d10453SEric Joyner /**
5472*71d10453SEric Joyner  * ice_rem_prof_id_flow - remove flow
5473*71d10453SEric Joyner  * @hw: pointer to the HW struct
5474*71d10453SEric Joyner  * @blk: hardware block
5475*71d10453SEric Joyner  * @vsi: the VSI from which to remove the profile specified by ID
5476*71d10453SEric Joyner  * @hdl: profile tracking handle
5477*71d10453SEric Joyner  *
5478*71d10453SEric Joyner  * Calling this function will update the hardware tables to remove the
5479*71d10453SEric Joyner  * profile indicated by the ID parameter for the VSIs specified in the VSI
5480*71d10453SEric Joyner  * array. Once successfully called, the flow will be disabled.
5481*71d10453SEric Joyner  */
5482*71d10453SEric Joyner enum ice_status
5483*71d10453SEric Joyner ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
5484*71d10453SEric Joyner {
5485*71d10453SEric Joyner 	struct ice_vsig_prof *tmp1, *del1;
5486*71d10453SEric Joyner 	struct LIST_HEAD_TYPE chg, copy;
5487*71d10453SEric Joyner 	struct ice_chs_chg *tmp, *del;
5488*71d10453SEric Joyner 	enum ice_status status;
5489*71d10453SEric Joyner 	u16 vsig;
5490*71d10453SEric Joyner 
5491*71d10453SEric Joyner 	INIT_LIST_HEAD(&copy);
5492*71d10453SEric Joyner 	INIT_LIST_HEAD(&chg);
5493*71d10453SEric Joyner 
5494*71d10453SEric Joyner 	/* determine if VSI is already part of a VSIG */
5495*71d10453SEric Joyner 	status = ice_vsig_find_vsi(hw, blk, vsi, &vsig);
5496*71d10453SEric Joyner 	if (!status && vsig) {
5497*71d10453SEric Joyner 		bool last_profile;
5498*71d10453SEric Joyner 		bool only_vsi;
5499*71d10453SEric Joyner 		u16 ref;
5500*71d10453SEric Joyner 
5501*71d10453SEric Joyner 		/* found in VSIG */
5502*71d10453SEric Joyner 		last_profile = ice_vsig_prof_id_count(hw, blk, vsig) == 1;
5503*71d10453SEric Joyner 		status = ice_vsig_get_ref(hw, blk, vsig, &ref);
5504*71d10453SEric Joyner 		if (status)
5505*71d10453SEric Joyner 			goto err_ice_rem_prof_id_flow;
5506*71d10453SEric Joyner 		only_vsi = (ref == 1);
5507*71d10453SEric Joyner 
5508*71d10453SEric Joyner 		if (only_vsi) {
5509*71d10453SEric Joyner 			/* If the original VSIG only contains one reference,
5510*71d10453SEric Joyner 			 * which will be the requesting VSI, then the VSI is not
5511*71d10453SEric Joyner 			 * sharing entries and we can simply remove the specific
5512*71d10453SEric Joyner 			 * characteristics from the VSIG.
5513*71d10453SEric Joyner 			 */
5514*71d10453SEric Joyner 
5515*71d10453SEric Joyner 			if (last_profile) {
5516*71d10453SEric Joyner 				/* If there are no profiles left for this VSIG,
5517*71d10453SEric Joyner 				 * then simply remove the the VSIG.
5518*71d10453SEric Joyner 				 */
5519*71d10453SEric Joyner 				status = ice_rem_vsig(hw, blk, vsig, &chg);
5520*71d10453SEric Joyner 				if (status)
5521*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5522*71d10453SEric Joyner 			} else {
5523*71d10453SEric Joyner 				status = ice_rem_prof_id_vsig(hw, blk, vsig,
5524*71d10453SEric Joyner 							      hdl, &chg);
5525*71d10453SEric Joyner 				if (status)
5526*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5527*71d10453SEric Joyner 
5528*71d10453SEric Joyner 				/* Adjust priorities */
5529*71d10453SEric Joyner 				status = ice_adj_prof_priorities(hw, blk, vsig,
5530*71d10453SEric Joyner 								 &chg);
5531*71d10453SEric Joyner 				if (status)
5532*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5533*71d10453SEric Joyner 			}
5534*71d10453SEric Joyner 
5535*71d10453SEric Joyner 		} else {
5536*71d10453SEric Joyner 			/* Make a copy of the VSIG's list of Profiles */
5537*71d10453SEric Joyner 			status = ice_get_profs_vsig(hw, blk, vsig, &copy);
5538*71d10453SEric Joyner 			if (status)
5539*71d10453SEric Joyner 				goto err_ice_rem_prof_id_flow;
5540*71d10453SEric Joyner 
5541*71d10453SEric Joyner 			/* Remove specified profile entry from the list */
5542*71d10453SEric Joyner 			status = ice_rem_prof_from_list(hw, &copy, hdl);
5543*71d10453SEric Joyner 			if (status)
5544*71d10453SEric Joyner 				goto err_ice_rem_prof_id_flow;
5545*71d10453SEric Joyner 
5546*71d10453SEric Joyner 			if (LIST_EMPTY(&copy)) {
5547*71d10453SEric Joyner 				status = ice_move_vsi(hw, blk, vsi,
5548*71d10453SEric Joyner 						      ICE_DEFAULT_VSIG, &chg);
5549*71d10453SEric Joyner 				if (status)
5550*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5551*71d10453SEric Joyner 
5552*71d10453SEric Joyner 			} else if (!ice_find_dup_props_vsig(hw, blk, &copy,
5553*71d10453SEric Joyner 							    &vsig)) {
5554*71d10453SEric Joyner 				/* found an exact match */
5555*71d10453SEric Joyner 				/* add or move VSI to the VSIG that matches */
5556*71d10453SEric Joyner 				/* Search for a VSIG with a matching profile
5557*71d10453SEric Joyner 				 * list
5558*71d10453SEric Joyner 				 */
5559*71d10453SEric Joyner 
5560*71d10453SEric Joyner 				/* Found match, move VSI to the matching VSIG */
5561*71d10453SEric Joyner 				status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
5562*71d10453SEric Joyner 				if (status)
5563*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5564*71d10453SEric Joyner 			} else {
5565*71d10453SEric Joyner 				/* since no existing VSIG supports this
5566*71d10453SEric Joyner 				 * characteristic pattern, we need to create a
5567*71d10453SEric Joyner 				 * new VSIG and TCAM entries
5568*71d10453SEric Joyner 				 */
5569*71d10453SEric Joyner 				status = ice_create_vsig_from_lst(hw, blk, vsi,
5570*71d10453SEric Joyner 								  &copy, &vsig,
5571*71d10453SEric Joyner 								  &chg);
5572*71d10453SEric Joyner 				if (status)
5573*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5574*71d10453SEric Joyner 
5575*71d10453SEric Joyner 				/* Adjust priorities */
5576*71d10453SEric Joyner 				status = ice_adj_prof_priorities(hw, blk, vsig,
5577*71d10453SEric Joyner 								 &chg);
5578*71d10453SEric Joyner 				if (status)
5579*71d10453SEric Joyner 					goto err_ice_rem_prof_id_flow;
5580*71d10453SEric Joyner 			}
5581*71d10453SEric Joyner 		}
5582*71d10453SEric Joyner 	} else {
5583*71d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
5584*71d10453SEric Joyner 	}
5585*71d10453SEric Joyner 
5586*71d10453SEric Joyner 	/* update hardware tables */
5587*71d10453SEric Joyner 	if (!status)
5588*71d10453SEric Joyner 		status = ice_upd_prof_hw(hw, blk, &chg);
5589*71d10453SEric Joyner 
5590*71d10453SEric Joyner err_ice_rem_prof_id_flow:
5591*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) {
5592*71d10453SEric Joyner 		LIST_DEL(&del->list_entry);
5593*71d10453SEric Joyner 		ice_free(hw, del);
5594*71d10453SEric Joyner 	}
5595*71d10453SEric Joyner 
5596*71d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(del1, tmp1, &copy, ice_vsig_prof, list) {
5597*71d10453SEric Joyner 		LIST_DEL(&del1->list);
5598*71d10453SEric Joyner 		ice_free(hw, del1);
5599*71d10453SEric Joyner 	}
5600*71d10453SEric Joyner 
5601*71d10453SEric Joyner 	return status;
5602*71d10453SEric Joyner }
5603*71d10453SEric Joyner 
5604*71d10453SEric Joyner /**
5605*71d10453SEric Joyner  * ice_rem_flow - remove flow
5606*71d10453SEric Joyner  * @hw: pointer to the HW struct
5607*71d10453SEric Joyner  * @blk: hardware block
5608*71d10453SEric Joyner  * @vsi: array of VSIs from which to remove the profile specified by ID
5609*71d10453SEric Joyner  * @count: number of elements in the VSI array
5610*71d10453SEric Joyner  * @id: profile tracking ID
5611*71d10453SEric Joyner  *
5612*71d10453SEric Joyner  * The function will remove flows from the specified VSIs that were enabled
5613*71d10453SEric Joyner  * using ice_add_flow. The ID value will indicated which profile will be
5614*71d10453SEric Joyner  * removed. Once successfully called, the flow will be disabled.
5615*71d10453SEric Joyner  */
5616*71d10453SEric Joyner enum ice_status
5617*71d10453SEric Joyner ice_rem_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count,
5618*71d10453SEric Joyner 	     u64 id)
5619*71d10453SEric Joyner {
5620*71d10453SEric Joyner 	enum ice_status status;
5621*71d10453SEric Joyner 	u16 i;
5622*71d10453SEric Joyner 
5623*71d10453SEric Joyner 	for (i = 0; i < count; i++) {
5624*71d10453SEric Joyner 		status = ice_rem_prof_id_flow(hw, blk, vsi[i], id);
5625*71d10453SEric Joyner 		if (status)
5626*71d10453SEric Joyner 			return status;
5627*71d10453SEric Joyner 	}
5628*71d10453SEric Joyner 
5629*71d10453SEric Joyner 	return ICE_SUCCESS;
5630*71d10453SEric Joyner }
5631