1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606 * Copyright(c) 2001-2020 Intel Corporation
3*2d9fd380Sjfb8856606 */
4*2d9fd380Sjfb8856606
5*2d9fd380Sjfb8856606 #include "ice_acl.h"
6*2d9fd380Sjfb8856606 #include "ice_flow.h"
7*2d9fd380Sjfb8856606
8*2d9fd380Sjfb8856606 /* Determine the TCAM index of entry 'e' within the ACL table */
9*2d9fd380Sjfb8856606 #define ICE_ACL_TBL_TCAM_IDX(e) ((e) / ICE_AQC_ACL_TCAM_DEPTH)
10*2d9fd380Sjfb8856606
11*2d9fd380Sjfb8856606 /* Determine the entry index within the TCAM */
12*2d9fd380Sjfb8856606 #define ICE_ACL_TBL_TCAM_ENTRY_IDX(e) ((e) % ICE_AQC_ACL_TCAM_DEPTH)
13*2d9fd380Sjfb8856606
14*2d9fd380Sjfb8856606 #define ICE_ACL_SCEN_ENTRY_INVAL 0xFFFF
15*2d9fd380Sjfb8856606
16*2d9fd380Sjfb8856606 /**
17*2d9fd380Sjfb8856606 * ice_acl_init_entry
18*2d9fd380Sjfb8856606 * @scen: pointer to the scenario struct
19*2d9fd380Sjfb8856606 *
20*2d9fd380Sjfb8856606 * Initialize the scenario control structure.
21*2d9fd380Sjfb8856606 */
ice_acl_init_entry(struct ice_acl_scen * scen)22*2d9fd380Sjfb8856606 static void ice_acl_init_entry(struct ice_acl_scen *scen)
23*2d9fd380Sjfb8856606 {
24*2d9fd380Sjfb8856606 /* low priority: start from the highest index, 25% of total entries
25*2d9fd380Sjfb8856606 * normal priority: start from the highest index, 50% of total entries
26*2d9fd380Sjfb8856606 * high priority: start from the lowest index, 25% of total entries
27*2d9fd380Sjfb8856606 */
28*2d9fd380Sjfb8856606 scen->first_idx[ICE_ACL_PRIO_LOW] = scen->num_entry - 1;
29*2d9fd380Sjfb8856606 scen->first_idx[ICE_ACL_PRIO_NORMAL] = scen->num_entry -
30*2d9fd380Sjfb8856606 scen->num_entry / 4 - 1;
31*2d9fd380Sjfb8856606 scen->first_idx[ICE_ACL_PRIO_HIGH] = 0;
32*2d9fd380Sjfb8856606
33*2d9fd380Sjfb8856606 scen->last_idx[ICE_ACL_PRIO_LOW] = scen->num_entry -
34*2d9fd380Sjfb8856606 scen->num_entry / 4;
35*2d9fd380Sjfb8856606 scen->last_idx[ICE_ACL_PRIO_NORMAL] = scen->num_entry / 4;
36*2d9fd380Sjfb8856606 scen->last_idx[ICE_ACL_PRIO_HIGH] = scen->num_entry / 4 - 1;
37*2d9fd380Sjfb8856606 }
38*2d9fd380Sjfb8856606
39*2d9fd380Sjfb8856606 /**
40*2d9fd380Sjfb8856606 * ice_acl_scen_assign_entry_idx
41*2d9fd380Sjfb8856606 * @scen: pointer to the scenario struct
42*2d9fd380Sjfb8856606 * @prio: the priority of the flow entry being allocated
43*2d9fd380Sjfb8856606 *
44*2d9fd380Sjfb8856606 * To find the index of an available entry in scenario
45*2d9fd380Sjfb8856606 *
46*2d9fd380Sjfb8856606 * Returns ICE_ACL_SCEN_ENTRY_INVAL if fails
47*2d9fd380Sjfb8856606 * Returns index on success
48*2d9fd380Sjfb8856606 */
49*2d9fd380Sjfb8856606 static u16
ice_acl_scen_assign_entry_idx(struct ice_acl_scen * scen,enum ice_acl_entry_prio prio)50*2d9fd380Sjfb8856606 ice_acl_scen_assign_entry_idx(struct ice_acl_scen *scen,
51*2d9fd380Sjfb8856606 enum ice_acl_entry_prio prio)
52*2d9fd380Sjfb8856606 {
53*2d9fd380Sjfb8856606 u16 first_idx, last_idx, i;
54*2d9fd380Sjfb8856606 s8 step;
55*2d9fd380Sjfb8856606
56*2d9fd380Sjfb8856606 if (prio >= ICE_ACL_MAX_PRIO)
57*2d9fd380Sjfb8856606 return ICE_ACL_SCEN_ENTRY_INVAL;
58*2d9fd380Sjfb8856606
59*2d9fd380Sjfb8856606 first_idx = scen->first_idx[prio];
60*2d9fd380Sjfb8856606 last_idx = scen->last_idx[prio];
61*2d9fd380Sjfb8856606 step = first_idx <= last_idx ? 1 : -1;
62*2d9fd380Sjfb8856606
63*2d9fd380Sjfb8856606 for (i = first_idx; i != last_idx + step; i += step)
64*2d9fd380Sjfb8856606 if (!ice_test_and_set_bit(i, scen->entry_bitmap))
65*2d9fd380Sjfb8856606 return i;
66*2d9fd380Sjfb8856606
67*2d9fd380Sjfb8856606 return ICE_ACL_SCEN_ENTRY_INVAL;
68*2d9fd380Sjfb8856606 }
69*2d9fd380Sjfb8856606
70*2d9fd380Sjfb8856606 /**
71*2d9fd380Sjfb8856606 * ice_acl_scen_free_entry_idx
72*2d9fd380Sjfb8856606 * @scen: pointer to the scenario struct
73*2d9fd380Sjfb8856606 * @idx: the index of the flow entry being de-allocated
74*2d9fd380Sjfb8856606 *
75*2d9fd380Sjfb8856606 * To mark an entry available in scenario
76*2d9fd380Sjfb8856606 */
77*2d9fd380Sjfb8856606 static enum ice_status
ice_acl_scen_free_entry_idx(struct ice_acl_scen * scen,u16 idx)78*2d9fd380Sjfb8856606 ice_acl_scen_free_entry_idx(struct ice_acl_scen *scen, u16 idx)
79*2d9fd380Sjfb8856606 {
80*2d9fd380Sjfb8856606 if (idx >= scen->num_entry)
81*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
82*2d9fd380Sjfb8856606
83*2d9fd380Sjfb8856606 if (!ice_test_and_clear_bit(idx, scen->entry_bitmap))
84*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
85*2d9fd380Sjfb8856606
86*2d9fd380Sjfb8856606 return ICE_SUCCESS;
87*2d9fd380Sjfb8856606 }
88*2d9fd380Sjfb8856606
89*2d9fd380Sjfb8856606 /**
90*2d9fd380Sjfb8856606 * ice_acl_tbl_calc_end_idx
91*2d9fd380Sjfb8856606 * @start: start index of the TCAM entry of this partition
92*2d9fd380Sjfb8856606 * @num_entries: number of entries in this partition
93*2d9fd380Sjfb8856606 * @width: width of a partition in number of TCAMs
94*2d9fd380Sjfb8856606 *
95*2d9fd380Sjfb8856606 * Calculate the end entry index for a partition with starting entry index
96*2d9fd380Sjfb8856606 * 'start', entries 'num_entries', and width 'width'.
97*2d9fd380Sjfb8856606 */
ice_acl_tbl_calc_end_idx(u16 start,u16 num_entries,u16 width)98*2d9fd380Sjfb8856606 static u16 ice_acl_tbl_calc_end_idx(u16 start, u16 num_entries, u16 width)
99*2d9fd380Sjfb8856606 {
100*2d9fd380Sjfb8856606 u16 end_idx, add_entries = 0;
101*2d9fd380Sjfb8856606
102*2d9fd380Sjfb8856606 end_idx = start + (num_entries - 1);
103*2d9fd380Sjfb8856606
104*2d9fd380Sjfb8856606 /* In case that our ACL partition requires cascading TCAMs */
105*2d9fd380Sjfb8856606 if (width > 1) {
106*2d9fd380Sjfb8856606 u16 num_stack_level;
107*2d9fd380Sjfb8856606
108*2d9fd380Sjfb8856606 /* Figure out the TCAM stacked level in this ACL scenario */
109*2d9fd380Sjfb8856606 num_stack_level = (start % ICE_AQC_ACL_TCAM_DEPTH) +
110*2d9fd380Sjfb8856606 num_entries;
111*2d9fd380Sjfb8856606 num_stack_level = DIVIDE_AND_ROUND_UP(num_stack_level,
112*2d9fd380Sjfb8856606 ICE_AQC_ACL_TCAM_DEPTH);
113*2d9fd380Sjfb8856606
114*2d9fd380Sjfb8856606 /* In this case, each entries in our ACL partition span
115*2d9fd380Sjfb8856606 * multiple TCAMs. Thus, we will need to add
116*2d9fd380Sjfb8856606 * ((width - 1) * num_stack_level) TCAM's entries to
117*2d9fd380Sjfb8856606 * end_idx.
118*2d9fd380Sjfb8856606 *
119*2d9fd380Sjfb8856606 * For example : In our case, our scenario is 2x2:
120*2d9fd380Sjfb8856606 * [TCAM 0] [TCAM 1]
121*2d9fd380Sjfb8856606 * [TCAM 2] [TCAM 3]
122*2d9fd380Sjfb8856606 * Assuming that a TCAM will have 512 entries. If "start"
123*2d9fd380Sjfb8856606 * is 500, "num_entries" is 3 and "width" = 2, then end_idx
124*2d9fd380Sjfb8856606 * should be 1024 (belongs to TCAM 2).
125*2d9fd380Sjfb8856606 * Before going to this if statement, end_idx will have the
126*2d9fd380Sjfb8856606 * value of 512. If "width" is 1, then the final value of
127*2d9fd380Sjfb8856606 * end_idx is 512. However, in our case, width is 2, then we
128*2d9fd380Sjfb8856606 * will need add (2 - 1) * 1 * 512. As result, end_idx will
129*2d9fd380Sjfb8856606 * have the value of 1024.
130*2d9fd380Sjfb8856606 */
131*2d9fd380Sjfb8856606 add_entries = (width - 1) * num_stack_level *
132*2d9fd380Sjfb8856606 ICE_AQC_ACL_TCAM_DEPTH;
133*2d9fd380Sjfb8856606 }
134*2d9fd380Sjfb8856606
135*2d9fd380Sjfb8856606 return end_idx + add_entries;
136*2d9fd380Sjfb8856606 }
137*2d9fd380Sjfb8856606
138*2d9fd380Sjfb8856606 /**
139*2d9fd380Sjfb8856606 * ice_acl_init_tbl
140*2d9fd380Sjfb8856606 * @hw: pointer to the hardware structure
141*2d9fd380Sjfb8856606 *
142*2d9fd380Sjfb8856606 * Initialize the ACL table by invalidating TCAM entries and action pairs.
143*2d9fd380Sjfb8856606 */
ice_acl_init_tbl(struct ice_hw * hw)144*2d9fd380Sjfb8856606 static enum ice_status ice_acl_init_tbl(struct ice_hw *hw)
145*2d9fd380Sjfb8856606 {
146*2d9fd380Sjfb8856606 struct ice_aqc_actpair act_buf;
147*2d9fd380Sjfb8856606 struct ice_aqc_acl_data buf;
148*2d9fd380Sjfb8856606 enum ice_status status = ICE_SUCCESS;
149*2d9fd380Sjfb8856606 struct ice_acl_tbl *tbl;
150*2d9fd380Sjfb8856606 u8 tcam_idx, i;
151*2d9fd380Sjfb8856606 u16 idx;
152*2d9fd380Sjfb8856606
153*2d9fd380Sjfb8856606 tbl = hw->acl_tbl;
154*2d9fd380Sjfb8856606 if (!tbl)
155*2d9fd380Sjfb8856606 return ICE_ERR_CFG;
156*2d9fd380Sjfb8856606
157*2d9fd380Sjfb8856606 ice_memset(&buf, 0, sizeof(buf), ICE_NONDMA_MEM);
158*2d9fd380Sjfb8856606 ice_memset(&act_buf, 0, sizeof(act_buf), ICE_NONDMA_MEM);
159*2d9fd380Sjfb8856606
160*2d9fd380Sjfb8856606 tcam_idx = tbl->first_tcam;
161*2d9fd380Sjfb8856606 idx = tbl->first_entry;
162*2d9fd380Sjfb8856606 while (tcam_idx < tbl->last_tcam ||
163*2d9fd380Sjfb8856606 (tcam_idx == tbl->last_tcam && idx <= tbl->last_entry)) {
164*2d9fd380Sjfb8856606 /* Use the same value for entry_key and entry_key_inv since
165*2d9fd380Sjfb8856606 * we are initializing the fields to 0
166*2d9fd380Sjfb8856606 */
167*2d9fd380Sjfb8856606 status = ice_aq_program_acl_entry(hw, tcam_idx, idx, &buf,
168*2d9fd380Sjfb8856606 NULL);
169*2d9fd380Sjfb8856606 if (status)
170*2d9fd380Sjfb8856606 return status;
171*2d9fd380Sjfb8856606
172*2d9fd380Sjfb8856606 if (++idx > tbl->last_entry) {
173*2d9fd380Sjfb8856606 tcam_idx++;
174*2d9fd380Sjfb8856606 idx = tbl->first_entry;
175*2d9fd380Sjfb8856606 }
176*2d9fd380Sjfb8856606 }
177*2d9fd380Sjfb8856606
178*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_MAX_ACTION_MEMORIES; i++) {
179*2d9fd380Sjfb8856606 u16 act_entry_idx, start, end;
180*2d9fd380Sjfb8856606
181*2d9fd380Sjfb8856606 if (tbl->act_mems[i].act_mem == ICE_ACL_ACT_PAIR_MEM_INVAL)
182*2d9fd380Sjfb8856606 continue;
183*2d9fd380Sjfb8856606
184*2d9fd380Sjfb8856606 start = tbl->first_entry;
185*2d9fd380Sjfb8856606 end = tbl->last_entry;
186*2d9fd380Sjfb8856606
187*2d9fd380Sjfb8856606 for (act_entry_idx = start; act_entry_idx <= end;
188*2d9fd380Sjfb8856606 act_entry_idx++) {
189*2d9fd380Sjfb8856606 /* Invalidate all allocated action pairs */
190*2d9fd380Sjfb8856606 status = ice_aq_program_actpair(hw, i, act_entry_idx,
191*2d9fd380Sjfb8856606 &act_buf, NULL);
192*2d9fd380Sjfb8856606 if (status)
193*2d9fd380Sjfb8856606 return status;
194*2d9fd380Sjfb8856606 }
195*2d9fd380Sjfb8856606 }
196*2d9fd380Sjfb8856606
197*2d9fd380Sjfb8856606 return status;
198*2d9fd380Sjfb8856606 }
199*2d9fd380Sjfb8856606
200*2d9fd380Sjfb8856606 /**
201*2d9fd380Sjfb8856606 * ice_acl_assign_act_mems_to_tcam
202*2d9fd380Sjfb8856606 * @tbl: pointer to ACL table structure
203*2d9fd380Sjfb8856606 * @cur_tcam: Index of current TCAM. Value = 0 to (ICE_AQC_ACL_SLICES - 1)
204*2d9fd380Sjfb8856606 * @cur_mem_idx: Index of current action memory bank. Value = 0 to
205*2d9fd380Sjfb8856606 * (ICE_AQC_MAX_ACTION_MEMORIES - 1)
206*2d9fd380Sjfb8856606 * @num_mem: Number of action memory banks for this TCAM
207*2d9fd380Sjfb8856606 *
208*2d9fd380Sjfb8856606 * Assign "num_mem" valid action memory banks from "curr_mem_idx" to
209*2d9fd380Sjfb8856606 * "curr_tcam" TCAM.
210*2d9fd380Sjfb8856606 */
211*2d9fd380Sjfb8856606 static void
ice_acl_assign_act_mems_to_tcam(struct ice_acl_tbl * tbl,u8 cur_tcam,u8 * cur_mem_idx,u8 num_mem)212*2d9fd380Sjfb8856606 ice_acl_assign_act_mems_to_tcam(struct ice_acl_tbl *tbl, u8 cur_tcam,
213*2d9fd380Sjfb8856606 u8 *cur_mem_idx, u8 num_mem)
214*2d9fd380Sjfb8856606 {
215*2d9fd380Sjfb8856606 u8 mem_cnt;
216*2d9fd380Sjfb8856606
217*2d9fd380Sjfb8856606 for (mem_cnt = 0;
218*2d9fd380Sjfb8856606 *cur_mem_idx < ICE_AQC_MAX_ACTION_MEMORIES && mem_cnt < num_mem;
219*2d9fd380Sjfb8856606 (*cur_mem_idx)++) {
220*2d9fd380Sjfb8856606 struct ice_acl_act_mem *p_mem = &tbl->act_mems[*cur_mem_idx];
221*2d9fd380Sjfb8856606
222*2d9fd380Sjfb8856606 if (p_mem->act_mem == ICE_ACL_ACT_PAIR_MEM_INVAL)
223*2d9fd380Sjfb8856606 continue;
224*2d9fd380Sjfb8856606
225*2d9fd380Sjfb8856606 p_mem->member_of_tcam = cur_tcam;
226*2d9fd380Sjfb8856606
227*2d9fd380Sjfb8856606 mem_cnt++;
228*2d9fd380Sjfb8856606 }
229*2d9fd380Sjfb8856606 }
230*2d9fd380Sjfb8856606
231*2d9fd380Sjfb8856606 /**
232*2d9fd380Sjfb8856606 * ice_acl_divide_act_mems_to_tcams
233*2d9fd380Sjfb8856606 * @tbl: pointer to ACL table structure
234*2d9fd380Sjfb8856606 *
235*2d9fd380Sjfb8856606 * Figure out how to divide given action memory banks to given TCAMs. This
236*2d9fd380Sjfb8856606 * division is for SW book keeping. In the time when scenario is created,
237*2d9fd380Sjfb8856606 * an action memory bank can be used for different TCAM.
238*2d9fd380Sjfb8856606 *
239*2d9fd380Sjfb8856606 * For example, given that we have 2x2 ACL table with each table entry has
240*2d9fd380Sjfb8856606 * 2 action memory pairs. As the result, we will have 4 TCAMs (T1,T2,T3,T4)
241*2d9fd380Sjfb8856606 * and 4 action memory banks (A1,A2,A3,A4)
242*2d9fd380Sjfb8856606 * [T1 - T2] { A1 - A2 }
243*2d9fd380Sjfb8856606 * [T3 - T4] { A3 - A4 }
244*2d9fd380Sjfb8856606 * In the time when we need to create a scenario, for example, 2x1 scenario,
245*2d9fd380Sjfb8856606 * we will use [T3,T4] in a cascaded layout. As it is a requirement that all
246*2d9fd380Sjfb8856606 * action memory banks in a cascaded TCAM's row will need to associate with
247*2d9fd380Sjfb8856606 * the last TCAM. Thus, we will associate action memory banks [A3] and [A4]
248*2d9fd380Sjfb8856606 * for TCAM [T4].
249*2d9fd380Sjfb8856606 * For SW book-keeping purpose, we will keep theoretical maps between TCAM
250*2d9fd380Sjfb8856606 * [Tn] to action memory bank [An].
251*2d9fd380Sjfb8856606 */
ice_acl_divide_act_mems_to_tcams(struct ice_acl_tbl * tbl)252*2d9fd380Sjfb8856606 static void ice_acl_divide_act_mems_to_tcams(struct ice_acl_tbl *tbl)
253*2d9fd380Sjfb8856606 {
254*2d9fd380Sjfb8856606 u16 num_cscd, stack_level, stack_idx, min_act_mem;
255*2d9fd380Sjfb8856606 u8 tcam_idx = tbl->first_tcam;
256*2d9fd380Sjfb8856606 u16 max_idx_to_get_extra;
257*2d9fd380Sjfb8856606 u8 mem_idx = 0;
258*2d9fd380Sjfb8856606
259*2d9fd380Sjfb8856606 /* Determine number of stacked TCAMs */
260*2d9fd380Sjfb8856606 stack_level = DIVIDE_AND_ROUND_UP(tbl->info.depth,
261*2d9fd380Sjfb8856606 ICE_AQC_ACL_TCAM_DEPTH);
262*2d9fd380Sjfb8856606
263*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAMs */
264*2d9fd380Sjfb8856606 num_cscd = DIVIDE_AND_ROUND_UP(tbl->info.width,
265*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
266*2d9fd380Sjfb8856606
267*2d9fd380Sjfb8856606 /* In a line of cascaded TCAM, given the number of action memory
268*2d9fd380Sjfb8856606 * banks per ACL table entry, we want to fairly divide these action
269*2d9fd380Sjfb8856606 * memory banks between these TCAMs.
270*2d9fd380Sjfb8856606 *
271*2d9fd380Sjfb8856606 * For example, there are 3 TCAMs (TCAM 3,4,5) in a line of
272*2d9fd380Sjfb8856606 * cascaded TCAM, and there are 7 act_mems for each ACL table entry.
273*2d9fd380Sjfb8856606 * The result is:
274*2d9fd380Sjfb8856606 * [TCAM_3 will have 3 act_mems]
275*2d9fd380Sjfb8856606 * [TCAM_4 will have 2 act_mems]
276*2d9fd380Sjfb8856606 * [TCAM_5 will have 2 act_mems]
277*2d9fd380Sjfb8856606 */
278*2d9fd380Sjfb8856606 min_act_mem = tbl->info.entry_act_pairs / num_cscd;
279*2d9fd380Sjfb8856606 max_idx_to_get_extra = tbl->info.entry_act_pairs % num_cscd;
280*2d9fd380Sjfb8856606
281*2d9fd380Sjfb8856606 for (stack_idx = 0; stack_idx < stack_level; stack_idx++) {
282*2d9fd380Sjfb8856606 u16 i;
283*2d9fd380Sjfb8856606
284*2d9fd380Sjfb8856606 for (i = 0; i < num_cscd; i++) {
285*2d9fd380Sjfb8856606 u8 total_act_mem = min_act_mem;
286*2d9fd380Sjfb8856606
287*2d9fd380Sjfb8856606 if (i < max_idx_to_get_extra)
288*2d9fd380Sjfb8856606 total_act_mem++;
289*2d9fd380Sjfb8856606
290*2d9fd380Sjfb8856606 ice_acl_assign_act_mems_to_tcam(tbl, tcam_idx,
291*2d9fd380Sjfb8856606 &mem_idx,
292*2d9fd380Sjfb8856606 total_act_mem);
293*2d9fd380Sjfb8856606
294*2d9fd380Sjfb8856606 tcam_idx++;
295*2d9fd380Sjfb8856606 }
296*2d9fd380Sjfb8856606 }
297*2d9fd380Sjfb8856606 }
298*2d9fd380Sjfb8856606
299*2d9fd380Sjfb8856606 /**
300*2d9fd380Sjfb8856606 * ice_acl_create_tbl
301*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
302*2d9fd380Sjfb8856606 * @params: parameters for the table to be created
303*2d9fd380Sjfb8856606 *
304*2d9fd380Sjfb8856606 * Create a LEM table for ACL usage. We are currently starting with some fixed
305*2d9fd380Sjfb8856606 * values for the size of the table, but this will need to grow as more flow
306*2d9fd380Sjfb8856606 * entries are added by the user level.
307*2d9fd380Sjfb8856606 */
308*2d9fd380Sjfb8856606 enum ice_status
ice_acl_create_tbl(struct ice_hw * hw,struct ice_acl_tbl_params * params)309*2d9fd380Sjfb8856606 ice_acl_create_tbl(struct ice_hw *hw, struct ice_acl_tbl_params *params)
310*2d9fd380Sjfb8856606 {
311*2d9fd380Sjfb8856606 u16 width, depth, first_e, last_e, i;
312*2d9fd380Sjfb8856606 struct ice_aqc_acl_generic *resp_buf;
313*2d9fd380Sjfb8856606 struct ice_acl_alloc_tbl tbl_alloc;
314*2d9fd380Sjfb8856606 struct ice_acl_tbl *tbl;
315*2d9fd380Sjfb8856606 enum ice_status status;
316*2d9fd380Sjfb8856606
317*2d9fd380Sjfb8856606 if (hw->acl_tbl)
318*2d9fd380Sjfb8856606 return ICE_ERR_ALREADY_EXISTS;
319*2d9fd380Sjfb8856606
320*2d9fd380Sjfb8856606 if (!params)
321*2d9fd380Sjfb8856606 return ICE_ERR_PARAM;
322*2d9fd380Sjfb8856606
323*2d9fd380Sjfb8856606 /* round up the width to the next TCAM width boundary. */
324*2d9fd380Sjfb8856606 width = ROUND_UP(params->width, (u16)ICE_AQC_ACL_KEY_WIDTH_BYTES);
325*2d9fd380Sjfb8856606 /* depth should be provided in chunk (64 entry) increments */
326*2d9fd380Sjfb8856606 depth = ICE_ALIGN(params->depth, ICE_ACL_ENTRY_ALLOC_UNIT);
327*2d9fd380Sjfb8856606
328*2d9fd380Sjfb8856606 if (params->entry_act_pairs < width / ICE_AQC_ACL_KEY_WIDTH_BYTES) {
329*2d9fd380Sjfb8856606 params->entry_act_pairs = width / ICE_AQC_ACL_KEY_WIDTH_BYTES;
330*2d9fd380Sjfb8856606
331*2d9fd380Sjfb8856606 if (params->entry_act_pairs > ICE_AQC_TBL_MAX_ACTION_PAIRS)
332*2d9fd380Sjfb8856606 params->entry_act_pairs = ICE_AQC_TBL_MAX_ACTION_PAIRS;
333*2d9fd380Sjfb8856606 }
334*2d9fd380Sjfb8856606
335*2d9fd380Sjfb8856606 /* Validate that width*depth will not exceed the TCAM limit */
336*2d9fd380Sjfb8856606 if ((DIVIDE_AND_ROUND_UP(depth, ICE_AQC_ACL_TCAM_DEPTH) *
337*2d9fd380Sjfb8856606 (width / ICE_AQC_ACL_KEY_WIDTH_BYTES)) > ICE_AQC_ACL_SLICES)
338*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
339*2d9fd380Sjfb8856606
340*2d9fd380Sjfb8856606 ice_memset(&tbl_alloc, 0, sizeof(tbl_alloc), ICE_NONDMA_MEM);
341*2d9fd380Sjfb8856606 tbl_alloc.width = width;
342*2d9fd380Sjfb8856606 tbl_alloc.depth = depth;
343*2d9fd380Sjfb8856606 tbl_alloc.act_pairs_per_entry = params->entry_act_pairs;
344*2d9fd380Sjfb8856606 tbl_alloc.concurr = params->concurr;
345*2d9fd380Sjfb8856606 /* Set dependent_alloc_id only for concurrent table type */
346*2d9fd380Sjfb8856606 if (params->concurr) {
347*2d9fd380Sjfb8856606 tbl_alloc.num_dependent_alloc_ids =
348*2d9fd380Sjfb8856606 ICE_AQC_MAX_CONCURRENT_ACL_TBL;
349*2d9fd380Sjfb8856606
350*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_MAX_CONCURRENT_ACL_TBL; i++)
351*2d9fd380Sjfb8856606 tbl_alloc.buf.data_buf.alloc_ids[i] =
352*2d9fd380Sjfb8856606 CPU_TO_LE16(params->dep_tbls[i]);
353*2d9fd380Sjfb8856606 }
354*2d9fd380Sjfb8856606
355*2d9fd380Sjfb8856606 /* call the AQ command to create the ACL table with these values */
356*2d9fd380Sjfb8856606 status = ice_aq_alloc_acl_tbl(hw, &tbl_alloc, NULL);
357*2d9fd380Sjfb8856606 if (status) {
358*2d9fd380Sjfb8856606 if (LE16_TO_CPU(tbl_alloc.buf.resp_buf.alloc_id) <
359*2d9fd380Sjfb8856606 ICE_AQC_ALLOC_ID_LESS_THAN_4K)
360*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "Alloc ACL table failed. Unavailable resource.\n");
361*2d9fd380Sjfb8856606 else
362*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "AQ allocation of ACL failed with error. status: %d\n",
363*2d9fd380Sjfb8856606 status);
364*2d9fd380Sjfb8856606 return status;
365*2d9fd380Sjfb8856606 }
366*2d9fd380Sjfb8856606
367*2d9fd380Sjfb8856606 tbl = (struct ice_acl_tbl *)ice_malloc(hw, sizeof(*tbl));
368*2d9fd380Sjfb8856606 if (!tbl) {
369*2d9fd380Sjfb8856606 status = ICE_ERR_NO_MEMORY;
370*2d9fd380Sjfb8856606
371*2d9fd380Sjfb8856606 goto out;
372*2d9fd380Sjfb8856606 }
373*2d9fd380Sjfb8856606
374*2d9fd380Sjfb8856606 resp_buf = &tbl_alloc.buf.resp_buf;
375*2d9fd380Sjfb8856606
376*2d9fd380Sjfb8856606 /* Retrieve information of the allocated table */
377*2d9fd380Sjfb8856606 tbl->id = LE16_TO_CPU(resp_buf->alloc_id);
378*2d9fd380Sjfb8856606 tbl->first_tcam = resp_buf->ops.table.first_tcam;
379*2d9fd380Sjfb8856606 tbl->last_tcam = resp_buf->ops.table.last_tcam;
380*2d9fd380Sjfb8856606 tbl->first_entry = LE16_TO_CPU(resp_buf->first_entry);
381*2d9fd380Sjfb8856606 tbl->last_entry = LE16_TO_CPU(resp_buf->last_entry);
382*2d9fd380Sjfb8856606
383*2d9fd380Sjfb8856606 tbl->info = *params;
384*2d9fd380Sjfb8856606 tbl->info.width = width;
385*2d9fd380Sjfb8856606 tbl->info.depth = depth;
386*2d9fd380Sjfb8856606 hw->acl_tbl = tbl;
387*2d9fd380Sjfb8856606
388*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_MAX_ACTION_MEMORIES; i++)
389*2d9fd380Sjfb8856606 tbl->act_mems[i].act_mem = resp_buf->act_mem[i];
390*2d9fd380Sjfb8856606
391*2d9fd380Sjfb8856606 /* Figure out which TCAMs that these newly allocated action memories
392*2d9fd380Sjfb8856606 * belong to.
393*2d9fd380Sjfb8856606 */
394*2d9fd380Sjfb8856606 ice_acl_divide_act_mems_to_tcams(tbl);
395*2d9fd380Sjfb8856606
396*2d9fd380Sjfb8856606 /* Initialize the resources allocated by invalidating all TCAM entries
397*2d9fd380Sjfb8856606 * and all the action pairs
398*2d9fd380Sjfb8856606 */
399*2d9fd380Sjfb8856606 status = ice_acl_init_tbl(hw);
400*2d9fd380Sjfb8856606 if (status) {
401*2d9fd380Sjfb8856606 ice_free(hw, tbl);
402*2d9fd380Sjfb8856606 hw->acl_tbl = NULL;
403*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "Initialization of TCAM entries failed. status: %d\n",
404*2d9fd380Sjfb8856606 status);
405*2d9fd380Sjfb8856606 goto out;
406*2d9fd380Sjfb8856606 }
407*2d9fd380Sjfb8856606
408*2d9fd380Sjfb8856606 first_e = (tbl->first_tcam * ICE_AQC_MAX_TCAM_ALLOC_UNITS) +
409*2d9fd380Sjfb8856606 (tbl->first_entry / ICE_ACL_ENTRY_ALLOC_UNIT);
410*2d9fd380Sjfb8856606 last_e = (tbl->last_tcam * ICE_AQC_MAX_TCAM_ALLOC_UNITS) +
411*2d9fd380Sjfb8856606 (tbl->last_entry / ICE_ACL_ENTRY_ALLOC_UNIT);
412*2d9fd380Sjfb8856606
413*2d9fd380Sjfb8856606 /* Indicate available entries in the table */
414*2d9fd380Sjfb8856606 ice_bitmap_set(tbl->avail, first_e, last_e - first_e + 1);
415*2d9fd380Sjfb8856606
416*2d9fd380Sjfb8856606 INIT_LIST_HEAD(&tbl->scens);
417*2d9fd380Sjfb8856606 out:
418*2d9fd380Sjfb8856606
419*2d9fd380Sjfb8856606 return status;
420*2d9fd380Sjfb8856606 }
421*2d9fd380Sjfb8856606
422*2d9fd380Sjfb8856606 /**
423*2d9fd380Sjfb8856606 * ice_acl_alloc_partition - Allocate a partition from the ACL table
424*2d9fd380Sjfb8856606 * @hw: pointer to the hardware structure
425*2d9fd380Sjfb8856606 * @req: info of partition being allocated
426*2d9fd380Sjfb8856606 */
427*2d9fd380Sjfb8856606 static enum ice_status
ice_acl_alloc_partition(struct ice_hw * hw,struct ice_acl_scen * req)428*2d9fd380Sjfb8856606 ice_acl_alloc_partition(struct ice_hw *hw, struct ice_acl_scen *req)
429*2d9fd380Sjfb8856606 {
430*2d9fd380Sjfb8856606 u16 start = 0, cnt = 0, off = 0;
431*2d9fd380Sjfb8856606 u16 width, r_entries, row;
432*2d9fd380Sjfb8856606 bool done = false;
433*2d9fd380Sjfb8856606 int dir;
434*2d9fd380Sjfb8856606
435*2d9fd380Sjfb8856606 /* Determine the number of TCAMs each entry overlaps */
436*2d9fd380Sjfb8856606 width = DIVIDE_AND_ROUND_UP(req->width, ICE_AQC_ACL_KEY_WIDTH_BYTES);
437*2d9fd380Sjfb8856606
438*2d9fd380Sjfb8856606 /* Check if we have enough TCAMs to accommodate the width */
439*2d9fd380Sjfb8856606 if (width > hw->acl_tbl->last_tcam - hw->acl_tbl->first_tcam + 1)
440*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
441*2d9fd380Sjfb8856606
442*2d9fd380Sjfb8856606 /* Number of entries must be multiple of ICE_ACL_ENTRY_ALLOC_UNIT's */
443*2d9fd380Sjfb8856606 r_entries = ICE_ALIGN(req->num_entry, ICE_ACL_ENTRY_ALLOC_UNIT);
444*2d9fd380Sjfb8856606
445*2d9fd380Sjfb8856606 /* To look for an available partition that can accommodate the request,
446*2d9fd380Sjfb8856606 * the process first logically arranges available TCAMs in rows such
447*2d9fd380Sjfb8856606 * that each row produces entries with the requested width. It then
448*2d9fd380Sjfb8856606 * scans the TCAMs' available bitmap, one bit at a time, and
449*2d9fd380Sjfb8856606 * accumulates contiguous available 64-entry chunks until there are
450*2d9fd380Sjfb8856606 * enough of them or when all TCAM configurations have been checked.
451*2d9fd380Sjfb8856606 *
452*2d9fd380Sjfb8856606 * For width of 1 TCAM, the scanning process starts from the top most
453*2d9fd380Sjfb8856606 * TCAM, and goes downward. Available bitmaps are examined from LSB
454*2d9fd380Sjfb8856606 * to MSB.
455*2d9fd380Sjfb8856606 *
456*2d9fd380Sjfb8856606 * For width of multiple TCAMs, the process starts from the bottom-most
457*2d9fd380Sjfb8856606 * row of TCAMs, and goes upward. Available bitmaps are examined from
458*2d9fd380Sjfb8856606 * the MSB to the LSB.
459*2d9fd380Sjfb8856606 *
460*2d9fd380Sjfb8856606 * To make sure that adjacent TCAMs can be logically arranged in the
461*2d9fd380Sjfb8856606 * same row, the scanning process may have multiple passes. In each
462*2d9fd380Sjfb8856606 * pass, the first TCAM of the bottom-most row is displaced by one
463*2d9fd380Sjfb8856606 * additional TCAM. The width of the row and the number of the TCAMs
464*2d9fd380Sjfb8856606 * available determine the number of passes. When the displacement is
465*2d9fd380Sjfb8856606 * more than the size of width, the TCAM row configurations will
466*2d9fd380Sjfb8856606 * repeat. The process will terminate when the configurations repeat.
467*2d9fd380Sjfb8856606 *
468*2d9fd380Sjfb8856606 * Available partitions can span more than one row of TCAMs.
469*2d9fd380Sjfb8856606 */
470*2d9fd380Sjfb8856606 if (width == 1) {
471*2d9fd380Sjfb8856606 row = hw->acl_tbl->first_tcam;
472*2d9fd380Sjfb8856606 dir = 1;
473*2d9fd380Sjfb8856606 } else {
474*2d9fd380Sjfb8856606 /* Start with the bottom-most row, and scan for available
475*2d9fd380Sjfb8856606 * entries upward
476*2d9fd380Sjfb8856606 */
477*2d9fd380Sjfb8856606 row = hw->acl_tbl->last_tcam + 1 - width;
478*2d9fd380Sjfb8856606 dir = -1;
479*2d9fd380Sjfb8856606 }
480*2d9fd380Sjfb8856606
481*2d9fd380Sjfb8856606 do {
482*2d9fd380Sjfb8856606 u16 i;
483*2d9fd380Sjfb8856606
484*2d9fd380Sjfb8856606 /* Scan all 64-entry chunks, one chunk at a time, in the
485*2d9fd380Sjfb8856606 * current TCAM row
486*2d9fd380Sjfb8856606 */
487*2d9fd380Sjfb8856606 for (i = 0;
488*2d9fd380Sjfb8856606 i < ICE_AQC_MAX_TCAM_ALLOC_UNITS && cnt < r_entries;
489*2d9fd380Sjfb8856606 i++) {
490*2d9fd380Sjfb8856606 bool avail = true;
491*2d9fd380Sjfb8856606 u16 w, p;
492*2d9fd380Sjfb8856606
493*2d9fd380Sjfb8856606 /* Compute the cumulative available mask across the
494*2d9fd380Sjfb8856606 * TCAM row to determine if the current 64-entry chunk
495*2d9fd380Sjfb8856606 * is available.
496*2d9fd380Sjfb8856606 */
497*2d9fd380Sjfb8856606 p = dir > 0 ? i : ICE_AQC_MAX_TCAM_ALLOC_UNITS - i - 1;
498*2d9fd380Sjfb8856606 for (w = row; w < row + width && avail; w++) {
499*2d9fd380Sjfb8856606 u16 b;
500*2d9fd380Sjfb8856606
501*2d9fd380Sjfb8856606 b = (w * ICE_AQC_MAX_TCAM_ALLOC_UNITS) + p;
502*2d9fd380Sjfb8856606 avail &= ice_is_bit_set(hw->acl_tbl->avail, b);
503*2d9fd380Sjfb8856606 }
504*2d9fd380Sjfb8856606
505*2d9fd380Sjfb8856606 if (!avail) {
506*2d9fd380Sjfb8856606 cnt = 0;
507*2d9fd380Sjfb8856606 } else {
508*2d9fd380Sjfb8856606 /* Compute the starting index of the newly
509*2d9fd380Sjfb8856606 * found partition. When 'dir' is negative, the
510*2d9fd380Sjfb8856606 * scan processes is going upward. If so, the
511*2d9fd380Sjfb8856606 * starting index needs to be updated for every
512*2d9fd380Sjfb8856606 * available 64-entry chunk found.
513*2d9fd380Sjfb8856606 */
514*2d9fd380Sjfb8856606 if (!cnt || dir < 0)
515*2d9fd380Sjfb8856606 start = (row * ICE_AQC_ACL_TCAM_DEPTH) +
516*2d9fd380Sjfb8856606 (p * ICE_ACL_ENTRY_ALLOC_UNIT);
517*2d9fd380Sjfb8856606 cnt += ICE_ACL_ENTRY_ALLOC_UNIT;
518*2d9fd380Sjfb8856606 }
519*2d9fd380Sjfb8856606 }
520*2d9fd380Sjfb8856606
521*2d9fd380Sjfb8856606 if (cnt >= r_entries) {
522*2d9fd380Sjfb8856606 req->start = start;
523*2d9fd380Sjfb8856606 req->num_entry = r_entries;
524*2d9fd380Sjfb8856606 req->end = ice_acl_tbl_calc_end_idx(start, r_entries,
525*2d9fd380Sjfb8856606 width);
526*2d9fd380Sjfb8856606 break;
527*2d9fd380Sjfb8856606 }
528*2d9fd380Sjfb8856606
529*2d9fd380Sjfb8856606 row = dir > 0 ? row + width : row - width;
530*2d9fd380Sjfb8856606 if (row > hw->acl_tbl->last_tcam ||
531*2d9fd380Sjfb8856606 row < hw->acl_tbl->first_tcam) {
532*2d9fd380Sjfb8856606 /* All rows have been checked. Increment 'off' that
533*2d9fd380Sjfb8856606 * will help yield a different TCAM configuration in
534*2d9fd380Sjfb8856606 * which adjacent TCAMs can be alternatively in the
535*2d9fd380Sjfb8856606 * same row.
536*2d9fd380Sjfb8856606 */
537*2d9fd380Sjfb8856606 off++;
538*2d9fd380Sjfb8856606
539*2d9fd380Sjfb8856606 /* However, if the new 'off' value yields previously
540*2d9fd380Sjfb8856606 * checked configurations, then exit.
541*2d9fd380Sjfb8856606 */
542*2d9fd380Sjfb8856606 if (off >= width)
543*2d9fd380Sjfb8856606 done = true;
544*2d9fd380Sjfb8856606 else
545*2d9fd380Sjfb8856606 row = dir > 0 ? off :
546*2d9fd380Sjfb8856606 hw->acl_tbl->last_tcam + 1 - off -
547*2d9fd380Sjfb8856606 width;
548*2d9fd380Sjfb8856606 }
549*2d9fd380Sjfb8856606 } while (!done);
550*2d9fd380Sjfb8856606
551*2d9fd380Sjfb8856606 return cnt >= r_entries ? ICE_SUCCESS : ICE_ERR_MAX_LIMIT;
552*2d9fd380Sjfb8856606 }
553*2d9fd380Sjfb8856606
554*2d9fd380Sjfb8856606 /**
555*2d9fd380Sjfb8856606 * ice_acl_fill_tcam_select
556*2d9fd380Sjfb8856606 * @scen_buf: Pointer to the scenario buffer that needs to be populated
557*2d9fd380Sjfb8856606 * @scen: Pointer to the available space for the scenario
558*2d9fd380Sjfb8856606 * @tcam_idx: Index of the TCAM used for this scenario
559*2d9fd380Sjfb8856606 * @tcam_idx_in_cascade : Local index of the TCAM in the cascade scenario
560*2d9fd380Sjfb8856606 *
561*2d9fd380Sjfb8856606 * For all TCAM that participate in this scenario, fill out the tcam_select
562*2d9fd380Sjfb8856606 * value.
563*2d9fd380Sjfb8856606 */
564*2d9fd380Sjfb8856606 static void
ice_acl_fill_tcam_select(struct ice_aqc_acl_scen * scen_buf,struct ice_acl_scen * scen,u16 tcam_idx,u16 tcam_idx_in_cascade)565*2d9fd380Sjfb8856606 ice_acl_fill_tcam_select(struct ice_aqc_acl_scen *scen_buf,
566*2d9fd380Sjfb8856606 struct ice_acl_scen *scen, u16 tcam_idx,
567*2d9fd380Sjfb8856606 u16 tcam_idx_in_cascade)
568*2d9fd380Sjfb8856606 {
569*2d9fd380Sjfb8856606 u16 cascade_cnt, idx;
570*2d9fd380Sjfb8856606 u8 j;
571*2d9fd380Sjfb8856606
572*2d9fd380Sjfb8856606 idx = tcam_idx_in_cascade * ICE_AQC_ACL_KEY_WIDTH_BYTES;
573*2d9fd380Sjfb8856606 cascade_cnt = DIVIDE_AND_ROUND_UP(scen->width,
574*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
575*2d9fd380Sjfb8856606
576*2d9fd380Sjfb8856606 /* For each scenario, we reserved last three bytes of scenario width for
577*2d9fd380Sjfb8856606 * profile ID, range checker, and packet direction. Thus, the last three
578*2d9fd380Sjfb8856606 * bytes of the last cascaded TCAMs will have value of 1st, 31st and
579*2d9fd380Sjfb8856606 * 32nd byte location of BYTE selection base.
580*2d9fd380Sjfb8856606 *
581*2d9fd380Sjfb8856606 * For other bytes in the TCAMs:
582*2d9fd380Sjfb8856606 * For non-cascade mode (1 TCAM wide) scenario, TCAM[x]'s Select {0-1}
583*2d9fd380Sjfb8856606 * select indices 0-1 of the Byte Selection Base
584*2d9fd380Sjfb8856606 * For cascade mode, the leftmost TCAM of the first cascade row selects
585*2d9fd380Sjfb8856606 * indices 0-4 of the Byte Selection Base; the second TCAM in the
586*2d9fd380Sjfb8856606 * cascade row selects indices starting with 5-n
587*2d9fd380Sjfb8856606 */
588*2d9fd380Sjfb8856606 for (j = 0; j < ICE_AQC_ACL_KEY_WIDTH_BYTES; j++) {
589*2d9fd380Sjfb8856606 /* PKT DIR uses the 1st location of Byte Selection Base: + 1 */
590*2d9fd380Sjfb8856606 u8 val = ICE_AQC_ACL_BYTE_SEL_BASE + 1 + idx;
591*2d9fd380Sjfb8856606
592*2d9fd380Sjfb8856606 if (tcam_idx_in_cascade == cascade_cnt - 1) {
593*2d9fd380Sjfb8856606 if (j == ICE_ACL_SCEN_RNG_CHK_IDX_IN_TCAM)
594*2d9fd380Sjfb8856606 val = ICE_AQC_ACL_BYTE_SEL_BASE_RNG_CHK;
595*2d9fd380Sjfb8856606 else if (j == ICE_ACL_SCEN_PID_IDX_IN_TCAM)
596*2d9fd380Sjfb8856606 val = ICE_AQC_ACL_BYTE_SEL_BASE_PID;
597*2d9fd380Sjfb8856606 else if (j == ICE_ACL_SCEN_PKT_DIR_IDX_IN_TCAM)
598*2d9fd380Sjfb8856606 val = ICE_AQC_ACL_BYTE_SEL_BASE_PKT_DIR;
599*2d9fd380Sjfb8856606 }
600*2d9fd380Sjfb8856606
601*2d9fd380Sjfb8856606 /* In case that scenario's width is greater than the width of
602*2d9fd380Sjfb8856606 * the Byte selection base, we will not assign a value to the
603*2d9fd380Sjfb8856606 * tcam_select[j]. As a result, the tcam_select[j] will have
604*2d9fd380Sjfb8856606 * default value which is zero.
605*2d9fd380Sjfb8856606 */
606*2d9fd380Sjfb8856606 if (val > ICE_AQC_ACL_BYTE_SEL_BASE_RNG_CHK)
607*2d9fd380Sjfb8856606 continue;
608*2d9fd380Sjfb8856606
609*2d9fd380Sjfb8856606 scen_buf->tcam_cfg[tcam_idx].tcam_select[j] = val;
610*2d9fd380Sjfb8856606
611*2d9fd380Sjfb8856606 idx++;
612*2d9fd380Sjfb8856606 }
613*2d9fd380Sjfb8856606 }
614*2d9fd380Sjfb8856606
615*2d9fd380Sjfb8856606 /**
616*2d9fd380Sjfb8856606 * ice_acl_set_scen_chnk_msk
617*2d9fd380Sjfb8856606 * @scen_buf: Pointer to the scenario buffer that needs to be populated
618*2d9fd380Sjfb8856606 * @scen: pointer to the available space for the scenario
619*2d9fd380Sjfb8856606 *
620*2d9fd380Sjfb8856606 * Set the chunk mask for the entries that will be used by this scenario
621*2d9fd380Sjfb8856606 */
622*2d9fd380Sjfb8856606 static void
ice_acl_set_scen_chnk_msk(struct ice_aqc_acl_scen * scen_buf,struct ice_acl_scen * scen)623*2d9fd380Sjfb8856606 ice_acl_set_scen_chnk_msk(struct ice_aqc_acl_scen *scen_buf,
624*2d9fd380Sjfb8856606 struct ice_acl_scen *scen)
625*2d9fd380Sjfb8856606 {
626*2d9fd380Sjfb8856606 u16 tcam_idx, num_cscd, units, cnt;
627*2d9fd380Sjfb8856606 u8 chnk_offst;
628*2d9fd380Sjfb8856606
629*2d9fd380Sjfb8856606 /* Determine the starting TCAM index and offset of the start entry */
630*2d9fd380Sjfb8856606 tcam_idx = ICE_ACL_TBL_TCAM_IDX(scen->start);
631*2d9fd380Sjfb8856606 chnk_offst = (u8)((scen->start % ICE_AQC_ACL_TCAM_DEPTH) /
632*2d9fd380Sjfb8856606 ICE_ACL_ENTRY_ALLOC_UNIT);
633*2d9fd380Sjfb8856606
634*2d9fd380Sjfb8856606 /* Entries are allocated and tracked in multiple of 64's */
635*2d9fd380Sjfb8856606 units = scen->num_entry / ICE_ACL_ENTRY_ALLOC_UNIT;
636*2d9fd380Sjfb8856606
637*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAMs */
638*2d9fd380Sjfb8856606 num_cscd = scen->width / ICE_AQC_ACL_KEY_WIDTH_BYTES;
639*2d9fd380Sjfb8856606
640*2d9fd380Sjfb8856606 for (cnt = 0; cnt < units; cnt++) {
641*2d9fd380Sjfb8856606 u16 i;
642*2d9fd380Sjfb8856606
643*2d9fd380Sjfb8856606 /* Set the corresponding bitmap of individual 64-entry
644*2d9fd380Sjfb8856606 * chunk spans across a cascade of 1 or more TCAMs
645*2d9fd380Sjfb8856606 * For each TCAM, there will be (ICE_AQC_ACL_TCAM_DEPTH
646*2d9fd380Sjfb8856606 * / ICE_ACL_ENTRY_ALLOC_UNIT) or 8 chunks.
647*2d9fd380Sjfb8856606 */
648*2d9fd380Sjfb8856606 for (i = tcam_idx; i < tcam_idx + num_cscd; i++)
649*2d9fd380Sjfb8856606 scen_buf->tcam_cfg[i].chnk_msk |= BIT(chnk_offst);
650*2d9fd380Sjfb8856606
651*2d9fd380Sjfb8856606 chnk_offst = (chnk_offst + 1) % ICE_AQC_MAX_TCAM_ALLOC_UNITS;
652*2d9fd380Sjfb8856606 if (!chnk_offst)
653*2d9fd380Sjfb8856606 tcam_idx += num_cscd;
654*2d9fd380Sjfb8856606 }
655*2d9fd380Sjfb8856606 }
656*2d9fd380Sjfb8856606
657*2d9fd380Sjfb8856606 /**
658*2d9fd380Sjfb8856606 * ice_acl_assign_act_mem_for_scen
659*2d9fd380Sjfb8856606 * @tbl: pointer to ACL table structure
660*2d9fd380Sjfb8856606 * @scen: pointer to the scenario struct
661*2d9fd380Sjfb8856606 * @scen_buf: pointer to the available space for the scenario
662*2d9fd380Sjfb8856606 * @current_tcam_idx: theoretical index of the TCAM that we associated those
663*2d9fd380Sjfb8856606 * action memory banks with, at the table creation time.
664*2d9fd380Sjfb8856606 * @target_tcam_idx: index of the TCAM that we want to associate those action
665*2d9fd380Sjfb8856606 * memory banks with.
666*2d9fd380Sjfb8856606 */
667*2d9fd380Sjfb8856606 static void
ice_acl_assign_act_mem_for_scen(struct ice_acl_tbl * tbl,struct ice_acl_scen * scen,struct ice_aqc_acl_scen * scen_buf,u8 current_tcam_idx,u8 target_tcam_idx)668*2d9fd380Sjfb8856606 ice_acl_assign_act_mem_for_scen(struct ice_acl_tbl *tbl,
669*2d9fd380Sjfb8856606 struct ice_acl_scen *scen,
670*2d9fd380Sjfb8856606 struct ice_aqc_acl_scen *scen_buf,
671*2d9fd380Sjfb8856606 u8 current_tcam_idx, u8 target_tcam_idx)
672*2d9fd380Sjfb8856606 {
673*2d9fd380Sjfb8856606 u8 i;
674*2d9fd380Sjfb8856606
675*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_MAX_ACTION_MEMORIES; i++) {
676*2d9fd380Sjfb8856606 struct ice_acl_act_mem *p_mem = &tbl->act_mems[i];
677*2d9fd380Sjfb8856606
678*2d9fd380Sjfb8856606 if (p_mem->act_mem == ICE_ACL_ACT_PAIR_MEM_INVAL ||
679*2d9fd380Sjfb8856606 p_mem->member_of_tcam != current_tcam_idx)
680*2d9fd380Sjfb8856606 continue;
681*2d9fd380Sjfb8856606
682*2d9fd380Sjfb8856606 scen_buf->act_mem_cfg[i] = target_tcam_idx;
683*2d9fd380Sjfb8856606 scen_buf->act_mem_cfg[i] |= ICE_AQC_ACL_SCE_ACT_MEM_EN;
684*2d9fd380Sjfb8856606 ice_set_bit(i, scen->act_mem_bitmap);
685*2d9fd380Sjfb8856606 }
686*2d9fd380Sjfb8856606 }
687*2d9fd380Sjfb8856606
688*2d9fd380Sjfb8856606 /**
689*2d9fd380Sjfb8856606 * ice_acl_commit_partition - Indicate if the specified partition is active
690*2d9fd380Sjfb8856606 * @hw: pointer to the hardware structure
691*2d9fd380Sjfb8856606 * @scen: pointer to the scenario struct
692*2d9fd380Sjfb8856606 * @commit: true if the partition is being commit
693*2d9fd380Sjfb8856606 */
694*2d9fd380Sjfb8856606 static void
ice_acl_commit_partition(struct ice_hw * hw,struct ice_acl_scen * scen,bool commit)695*2d9fd380Sjfb8856606 ice_acl_commit_partition(struct ice_hw *hw, struct ice_acl_scen *scen,
696*2d9fd380Sjfb8856606 bool commit)
697*2d9fd380Sjfb8856606 {
698*2d9fd380Sjfb8856606 u16 tcam_idx, off, num_cscd, units, cnt;
699*2d9fd380Sjfb8856606
700*2d9fd380Sjfb8856606 /* Determine the starting TCAM index and offset of the start entry */
701*2d9fd380Sjfb8856606 tcam_idx = ICE_ACL_TBL_TCAM_IDX(scen->start);
702*2d9fd380Sjfb8856606 off = (scen->start % ICE_AQC_ACL_TCAM_DEPTH) /
703*2d9fd380Sjfb8856606 ICE_ACL_ENTRY_ALLOC_UNIT;
704*2d9fd380Sjfb8856606
705*2d9fd380Sjfb8856606 /* Entries are allocated and tracked in multiple of 64's */
706*2d9fd380Sjfb8856606 units = scen->num_entry / ICE_ACL_ENTRY_ALLOC_UNIT;
707*2d9fd380Sjfb8856606
708*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAM */
709*2d9fd380Sjfb8856606 num_cscd = scen->width / ICE_AQC_ACL_KEY_WIDTH_BYTES;
710*2d9fd380Sjfb8856606
711*2d9fd380Sjfb8856606 for (cnt = 0; cnt < units; cnt++) {
712*2d9fd380Sjfb8856606 u16 w;
713*2d9fd380Sjfb8856606
714*2d9fd380Sjfb8856606 /* Set/clear the corresponding bitmap of individual 64-entry
715*2d9fd380Sjfb8856606 * chunk spans across a row of 1 or more TCAMs
716*2d9fd380Sjfb8856606 */
717*2d9fd380Sjfb8856606 for (w = 0; w < num_cscd; w++) {
718*2d9fd380Sjfb8856606 u16 b;
719*2d9fd380Sjfb8856606
720*2d9fd380Sjfb8856606 b = ((tcam_idx + w) * ICE_AQC_MAX_TCAM_ALLOC_UNITS) +
721*2d9fd380Sjfb8856606 off;
722*2d9fd380Sjfb8856606 if (commit)
723*2d9fd380Sjfb8856606 ice_set_bit(b, hw->acl_tbl->avail);
724*2d9fd380Sjfb8856606 else
725*2d9fd380Sjfb8856606 ice_clear_bit(b, hw->acl_tbl->avail);
726*2d9fd380Sjfb8856606 }
727*2d9fd380Sjfb8856606
728*2d9fd380Sjfb8856606 off = (off + 1) % ICE_AQC_MAX_TCAM_ALLOC_UNITS;
729*2d9fd380Sjfb8856606 if (!off)
730*2d9fd380Sjfb8856606 tcam_idx += num_cscd;
731*2d9fd380Sjfb8856606 }
732*2d9fd380Sjfb8856606 }
733*2d9fd380Sjfb8856606
734*2d9fd380Sjfb8856606 /**
735*2d9fd380Sjfb8856606 * ice_acl_create_scen
736*2d9fd380Sjfb8856606 * @hw: pointer to the hardware structure
737*2d9fd380Sjfb8856606 * @match_width: number of bytes to be matched in this scenario
738*2d9fd380Sjfb8856606 * @num_entries: number of entries to be allocated for the scenario
739*2d9fd380Sjfb8856606 * @scen_id: holds returned scenario ID if successful
740*2d9fd380Sjfb8856606 */
741*2d9fd380Sjfb8856606 enum ice_status
ice_acl_create_scen(struct ice_hw * hw,u16 match_width,u16 num_entries,u16 * scen_id)742*2d9fd380Sjfb8856606 ice_acl_create_scen(struct ice_hw *hw, u16 match_width, u16 num_entries,
743*2d9fd380Sjfb8856606 u16 *scen_id)
744*2d9fd380Sjfb8856606 {
745*2d9fd380Sjfb8856606 u8 cascade_cnt, first_tcam, last_tcam, i, k;
746*2d9fd380Sjfb8856606 struct ice_aqc_acl_scen scen_buf;
747*2d9fd380Sjfb8856606 struct ice_acl_scen *scen;
748*2d9fd380Sjfb8856606 enum ice_status status;
749*2d9fd380Sjfb8856606
750*2d9fd380Sjfb8856606 if (!hw->acl_tbl)
751*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
752*2d9fd380Sjfb8856606
753*2d9fd380Sjfb8856606 scen = (struct ice_acl_scen *)ice_malloc(hw, sizeof(*scen));
754*2d9fd380Sjfb8856606 if (!scen)
755*2d9fd380Sjfb8856606 return ICE_ERR_NO_MEMORY;
756*2d9fd380Sjfb8856606
757*2d9fd380Sjfb8856606 scen->start = hw->acl_tbl->first_entry;
758*2d9fd380Sjfb8856606 scen->width = ICE_AQC_ACL_KEY_WIDTH_BYTES *
759*2d9fd380Sjfb8856606 DIVIDE_AND_ROUND_UP(match_width, ICE_AQC_ACL_KEY_WIDTH_BYTES);
760*2d9fd380Sjfb8856606 scen->num_entry = num_entries;
761*2d9fd380Sjfb8856606
762*2d9fd380Sjfb8856606 status = ice_acl_alloc_partition(hw, scen);
763*2d9fd380Sjfb8856606 if (status)
764*2d9fd380Sjfb8856606 goto out;
765*2d9fd380Sjfb8856606
766*2d9fd380Sjfb8856606 ice_memset(&scen_buf, 0, sizeof(scen_buf), ICE_NONDMA_MEM);
767*2d9fd380Sjfb8856606
768*2d9fd380Sjfb8856606 /* Determine the number of cascade TCAMs, given the scenario's width */
769*2d9fd380Sjfb8856606 cascade_cnt = DIVIDE_AND_ROUND_UP(scen->width,
770*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
771*2d9fd380Sjfb8856606 first_tcam = ICE_ACL_TBL_TCAM_IDX(scen->start);
772*2d9fd380Sjfb8856606 last_tcam = ICE_ACL_TBL_TCAM_IDX(scen->end);
773*2d9fd380Sjfb8856606
774*2d9fd380Sjfb8856606 /* For each scenario, we reserved last three bytes of scenario width for
775*2d9fd380Sjfb8856606 * packet direction flag, profile ID and range checker. Thus, we want to
776*2d9fd380Sjfb8856606 * return back to the caller the eff_width, pkt_dir_idx, rng_chk_idx and
777*2d9fd380Sjfb8856606 * pid_idx.
778*2d9fd380Sjfb8856606 */
779*2d9fd380Sjfb8856606 scen->eff_width = cascade_cnt * ICE_AQC_ACL_KEY_WIDTH_BYTES -
780*2d9fd380Sjfb8856606 ICE_ACL_SCEN_MIN_WIDTH;
781*2d9fd380Sjfb8856606 scen->rng_chk_idx = (cascade_cnt - 1) * ICE_AQC_ACL_KEY_WIDTH_BYTES +
782*2d9fd380Sjfb8856606 ICE_ACL_SCEN_RNG_CHK_IDX_IN_TCAM;
783*2d9fd380Sjfb8856606 scen->pid_idx = (cascade_cnt - 1) * ICE_AQC_ACL_KEY_WIDTH_BYTES +
784*2d9fd380Sjfb8856606 ICE_ACL_SCEN_PID_IDX_IN_TCAM;
785*2d9fd380Sjfb8856606 scen->pkt_dir_idx = (cascade_cnt - 1) * ICE_AQC_ACL_KEY_WIDTH_BYTES +
786*2d9fd380Sjfb8856606 ICE_ACL_SCEN_PKT_DIR_IDX_IN_TCAM;
787*2d9fd380Sjfb8856606
788*2d9fd380Sjfb8856606 /* set the chunk mask for the tcams */
789*2d9fd380Sjfb8856606 ice_acl_set_scen_chnk_msk(&scen_buf, scen);
790*2d9fd380Sjfb8856606
791*2d9fd380Sjfb8856606 /* set the TCAM select and start_cmp and start_set bits */
792*2d9fd380Sjfb8856606 k = first_tcam;
793*2d9fd380Sjfb8856606 /* set the START_SET bit at the beginning of the stack */
794*2d9fd380Sjfb8856606 scen_buf.tcam_cfg[k].start_cmp_set |= ICE_AQC_ACL_ALLOC_SCE_START_SET;
795*2d9fd380Sjfb8856606 while (k <= last_tcam) {
796*2d9fd380Sjfb8856606 u8 last_tcam_idx_cascade = cascade_cnt + k - 1;
797*2d9fd380Sjfb8856606
798*2d9fd380Sjfb8856606 /* set start_cmp for the first cascaded TCAM */
799*2d9fd380Sjfb8856606 scen_buf.tcam_cfg[k].start_cmp_set |=
800*2d9fd380Sjfb8856606 ICE_AQC_ACL_ALLOC_SCE_START_CMP;
801*2d9fd380Sjfb8856606
802*2d9fd380Sjfb8856606 /* cascade TCAMs up to the width of the scenario */
803*2d9fd380Sjfb8856606 for (i = k; i < cascade_cnt + k; i++) {
804*2d9fd380Sjfb8856606 ice_acl_fill_tcam_select(&scen_buf, scen, i, i - k);
805*2d9fd380Sjfb8856606 ice_acl_assign_act_mem_for_scen(hw->acl_tbl, scen,
806*2d9fd380Sjfb8856606 &scen_buf,
807*2d9fd380Sjfb8856606 i,
808*2d9fd380Sjfb8856606 last_tcam_idx_cascade);
809*2d9fd380Sjfb8856606 }
810*2d9fd380Sjfb8856606
811*2d9fd380Sjfb8856606 k = i;
812*2d9fd380Sjfb8856606 }
813*2d9fd380Sjfb8856606
814*2d9fd380Sjfb8856606 /* We need to set the start_cmp bit for the unused TCAMs. */
815*2d9fd380Sjfb8856606 i = 0;
816*2d9fd380Sjfb8856606 while (i < first_tcam)
817*2d9fd380Sjfb8856606 scen_buf.tcam_cfg[i++].start_cmp_set =
818*2d9fd380Sjfb8856606 ICE_AQC_ACL_ALLOC_SCE_START_CMP;
819*2d9fd380Sjfb8856606
820*2d9fd380Sjfb8856606 i = last_tcam + 1;
821*2d9fd380Sjfb8856606 while (i < ICE_AQC_ACL_SLICES)
822*2d9fd380Sjfb8856606 scen_buf.tcam_cfg[i++].start_cmp_set =
823*2d9fd380Sjfb8856606 ICE_AQC_ACL_ALLOC_SCE_START_CMP;
824*2d9fd380Sjfb8856606
825*2d9fd380Sjfb8856606 status = ice_aq_alloc_acl_scen(hw, scen_id, &scen_buf, NULL);
826*2d9fd380Sjfb8856606 if (status) {
827*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "AQ allocation of ACL scenario failed. status: %d\n",
828*2d9fd380Sjfb8856606 status);
829*2d9fd380Sjfb8856606 goto out;
830*2d9fd380Sjfb8856606 }
831*2d9fd380Sjfb8856606
832*2d9fd380Sjfb8856606 scen->id = *scen_id;
833*2d9fd380Sjfb8856606 ice_acl_commit_partition(hw, scen, false);
834*2d9fd380Sjfb8856606 ice_acl_init_entry(scen);
835*2d9fd380Sjfb8856606 LIST_ADD(&scen->list_entry, &hw->acl_tbl->scens);
836*2d9fd380Sjfb8856606
837*2d9fd380Sjfb8856606 out:
838*2d9fd380Sjfb8856606 if (status)
839*2d9fd380Sjfb8856606 ice_free(hw, scen);
840*2d9fd380Sjfb8856606
841*2d9fd380Sjfb8856606 return status;
842*2d9fd380Sjfb8856606 }
843*2d9fd380Sjfb8856606
844*2d9fd380Sjfb8856606 /**
845*2d9fd380Sjfb8856606 * ice_acl_destroy_scen - Destroy an ACL scenario
846*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
847*2d9fd380Sjfb8856606 * @scen_id: ID of the remove scenario
848*2d9fd380Sjfb8856606 */
ice_acl_destroy_scen(struct ice_hw * hw,u16 scen_id)849*2d9fd380Sjfb8856606 static enum ice_status ice_acl_destroy_scen(struct ice_hw *hw, u16 scen_id)
850*2d9fd380Sjfb8856606 {
851*2d9fd380Sjfb8856606 struct ice_acl_scen *scen, *tmp_scen;
852*2d9fd380Sjfb8856606 struct ice_flow_prof *p, *tmp;
853*2d9fd380Sjfb8856606 enum ice_status status;
854*2d9fd380Sjfb8856606
855*2d9fd380Sjfb8856606 if (!hw->acl_tbl)
856*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
857*2d9fd380Sjfb8856606
858*2d9fd380Sjfb8856606 /* Remove profiles that use "scen_id" scenario */
859*2d9fd380Sjfb8856606 LIST_FOR_EACH_ENTRY_SAFE(p, tmp, &hw->fl_profs[ICE_BLK_ACL],
860*2d9fd380Sjfb8856606 ice_flow_prof, l_entry)
861*2d9fd380Sjfb8856606 if (p->cfg.scen && p->cfg.scen->id == scen_id) {
862*2d9fd380Sjfb8856606 status = ice_flow_rem_prof(hw, ICE_BLK_ACL, p->id);
863*2d9fd380Sjfb8856606 if (status) {
864*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "ice_flow_rem_prof failed. status: %d\n",
865*2d9fd380Sjfb8856606 status);
866*2d9fd380Sjfb8856606 return status;
867*2d9fd380Sjfb8856606 }
868*2d9fd380Sjfb8856606 }
869*2d9fd380Sjfb8856606
870*2d9fd380Sjfb8856606 /* Call the AQ command to destroy the targeted scenario */
871*2d9fd380Sjfb8856606 status = ice_aq_dealloc_acl_scen(hw, scen_id, NULL);
872*2d9fd380Sjfb8856606 if (status) {
873*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "AQ de-allocation of scenario failed. status: %d\n",
874*2d9fd380Sjfb8856606 status);
875*2d9fd380Sjfb8856606 return status;
876*2d9fd380Sjfb8856606 }
877*2d9fd380Sjfb8856606
878*2d9fd380Sjfb8856606 /* Remove scenario from hw->acl_tbl->scens */
879*2d9fd380Sjfb8856606 LIST_FOR_EACH_ENTRY_SAFE(scen, tmp_scen, &hw->acl_tbl->scens,
880*2d9fd380Sjfb8856606 ice_acl_scen, list_entry)
881*2d9fd380Sjfb8856606 if (scen->id == scen_id) {
882*2d9fd380Sjfb8856606 LIST_DEL(&scen->list_entry);
883*2d9fd380Sjfb8856606 ice_free(hw, scen);
884*2d9fd380Sjfb8856606 }
885*2d9fd380Sjfb8856606
886*2d9fd380Sjfb8856606 return ICE_SUCCESS;
887*2d9fd380Sjfb8856606 }
888*2d9fd380Sjfb8856606
889*2d9fd380Sjfb8856606 /**
890*2d9fd380Sjfb8856606 * ice_acl_destroy_tbl - Destroy a previously created LEM table for ACL
891*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
892*2d9fd380Sjfb8856606 */
ice_acl_destroy_tbl(struct ice_hw * hw)893*2d9fd380Sjfb8856606 enum ice_status ice_acl_destroy_tbl(struct ice_hw *hw)
894*2d9fd380Sjfb8856606 {
895*2d9fd380Sjfb8856606 struct ice_acl_scen *pos_scen, *tmp_scen;
896*2d9fd380Sjfb8856606 struct ice_aqc_acl_generic resp_buf;
897*2d9fd380Sjfb8856606 struct ice_aqc_acl_scen buf;
898*2d9fd380Sjfb8856606 enum ice_status status;
899*2d9fd380Sjfb8856606 u8 i;
900*2d9fd380Sjfb8856606
901*2d9fd380Sjfb8856606 if (!hw->acl_tbl)
902*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
903*2d9fd380Sjfb8856606
904*2d9fd380Sjfb8856606 /* Mark all the created scenario's TCAM to stop the packet lookup and
905*2d9fd380Sjfb8856606 * delete them afterward
906*2d9fd380Sjfb8856606 */
907*2d9fd380Sjfb8856606 LIST_FOR_EACH_ENTRY_SAFE(pos_scen, tmp_scen, &hw->acl_tbl->scens,
908*2d9fd380Sjfb8856606 ice_acl_scen, list_entry) {
909*2d9fd380Sjfb8856606 status = ice_aq_query_acl_scen(hw, pos_scen->id, &buf, NULL);
910*2d9fd380Sjfb8856606 if (status) {
911*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "ice_aq_query_acl_scen() failed. status: %d\n",
912*2d9fd380Sjfb8856606 status);
913*2d9fd380Sjfb8856606 return status;
914*2d9fd380Sjfb8856606 }
915*2d9fd380Sjfb8856606
916*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_ACL_SLICES; i++) {
917*2d9fd380Sjfb8856606 buf.tcam_cfg[i].chnk_msk = 0;
918*2d9fd380Sjfb8856606 buf.tcam_cfg[i].start_cmp_set =
919*2d9fd380Sjfb8856606 ICE_AQC_ACL_ALLOC_SCE_START_CMP;
920*2d9fd380Sjfb8856606 }
921*2d9fd380Sjfb8856606
922*2d9fd380Sjfb8856606 for (i = 0; i < ICE_AQC_MAX_ACTION_MEMORIES; i++)
923*2d9fd380Sjfb8856606 buf.act_mem_cfg[i] = 0;
924*2d9fd380Sjfb8856606
925*2d9fd380Sjfb8856606 status = ice_aq_update_acl_scen(hw, pos_scen->id, &buf, NULL);
926*2d9fd380Sjfb8856606 if (status) {
927*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "ice_aq_update_acl_scen() failed. status: %d\n",
928*2d9fd380Sjfb8856606 status);
929*2d9fd380Sjfb8856606 return status;
930*2d9fd380Sjfb8856606 }
931*2d9fd380Sjfb8856606
932*2d9fd380Sjfb8856606 status = ice_acl_destroy_scen(hw, pos_scen->id);
933*2d9fd380Sjfb8856606 if (status) {
934*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "deletion of scenario failed. status: %d\n",
935*2d9fd380Sjfb8856606 status);
936*2d9fd380Sjfb8856606 return status;
937*2d9fd380Sjfb8856606 }
938*2d9fd380Sjfb8856606 }
939*2d9fd380Sjfb8856606
940*2d9fd380Sjfb8856606 /* call the AQ command to destroy the ACL table */
941*2d9fd380Sjfb8856606 status = ice_aq_dealloc_acl_tbl(hw, hw->acl_tbl->id, &resp_buf, NULL);
942*2d9fd380Sjfb8856606 if (status) {
943*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "AQ de-allocation of ACL failed. status: %d\n",
944*2d9fd380Sjfb8856606 status);
945*2d9fd380Sjfb8856606 return status;
946*2d9fd380Sjfb8856606 }
947*2d9fd380Sjfb8856606
948*2d9fd380Sjfb8856606 ice_free(hw, hw->acl_tbl);
949*2d9fd380Sjfb8856606 hw->acl_tbl = NULL;
950*2d9fd380Sjfb8856606
951*2d9fd380Sjfb8856606 return ICE_SUCCESS;
952*2d9fd380Sjfb8856606 }
953*2d9fd380Sjfb8856606
954*2d9fd380Sjfb8856606 /**
955*2d9fd380Sjfb8856606 * ice_acl_add_entry - Add a flow entry to an ACL scenario
956*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
957*2d9fd380Sjfb8856606 * @scen: scenario to add the entry to
958*2d9fd380Sjfb8856606 * @prio: priority level of the entry being added
959*2d9fd380Sjfb8856606 * @keys: buffer of the value of the key to be programmed to the ACL entry
960*2d9fd380Sjfb8856606 * @inverts: buffer of the value of the key inverts to be programmed
961*2d9fd380Sjfb8856606 * @acts: pointer to a buffer containing formatted actions
962*2d9fd380Sjfb8856606 * @acts_cnt: indicates the number of actions stored in "acts"
963*2d9fd380Sjfb8856606 * @entry_idx: returned scenario relative index of the added flow entry
964*2d9fd380Sjfb8856606 *
965*2d9fd380Sjfb8856606 * Given an ACL table and a scenario, to add the specified key and key invert
966*2d9fd380Sjfb8856606 * to an available entry in the specified scenario.
967*2d9fd380Sjfb8856606 * The "keys" and "inverts" buffers must be of the size which is the same as
968*2d9fd380Sjfb8856606 * the scenario's width
969*2d9fd380Sjfb8856606 */
970*2d9fd380Sjfb8856606 enum ice_status
ice_acl_add_entry(struct ice_hw * hw,struct ice_acl_scen * scen,enum ice_acl_entry_prio prio,u8 * keys,u8 * inverts,struct ice_acl_act_entry * acts,u8 acts_cnt,u16 * entry_idx)971*2d9fd380Sjfb8856606 ice_acl_add_entry(struct ice_hw *hw, struct ice_acl_scen *scen,
972*2d9fd380Sjfb8856606 enum ice_acl_entry_prio prio, u8 *keys, u8 *inverts,
973*2d9fd380Sjfb8856606 struct ice_acl_act_entry *acts, u8 acts_cnt, u16 *entry_idx)
974*2d9fd380Sjfb8856606 {
975*2d9fd380Sjfb8856606 u8 i, entry_tcam, num_cscd, offset;
976*2d9fd380Sjfb8856606 struct ice_aqc_acl_data buf;
977*2d9fd380Sjfb8856606 enum ice_status status = ICE_SUCCESS;
978*2d9fd380Sjfb8856606 u16 idx;
979*2d9fd380Sjfb8856606
980*2d9fd380Sjfb8856606 if (!scen)
981*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
982*2d9fd380Sjfb8856606
983*2d9fd380Sjfb8856606 *entry_idx = ice_acl_scen_assign_entry_idx(scen, prio);
984*2d9fd380Sjfb8856606 if (*entry_idx >= scen->num_entry) {
985*2d9fd380Sjfb8856606 *entry_idx = 0;
986*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
987*2d9fd380Sjfb8856606 }
988*2d9fd380Sjfb8856606
989*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAMs */
990*2d9fd380Sjfb8856606 num_cscd = DIVIDE_AND_ROUND_UP(scen->width,
991*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
992*2d9fd380Sjfb8856606
993*2d9fd380Sjfb8856606 entry_tcam = ICE_ACL_TBL_TCAM_IDX(scen->start);
994*2d9fd380Sjfb8856606 idx = ICE_ACL_TBL_TCAM_ENTRY_IDX(scen->start + *entry_idx);
995*2d9fd380Sjfb8856606
996*2d9fd380Sjfb8856606 ice_memset(&buf, 0, sizeof(buf), ICE_NONDMA_MEM);
997*2d9fd380Sjfb8856606 for (i = 0; i < num_cscd; i++) {
998*2d9fd380Sjfb8856606 /* If the key spans more than one TCAM in the case of cascaded
999*2d9fd380Sjfb8856606 * TCAMs, the key and key inverts need to be properly split
1000*2d9fd380Sjfb8856606 * among TCAMs.E.g.bytes 0 - 4 go to an index in the first TCAM
1001*2d9fd380Sjfb8856606 * and bytes 5 - 9 go to the same index in the next TCAM, etc.
1002*2d9fd380Sjfb8856606 * If the entry spans more than one TCAM in a cascaded TCAM
1003*2d9fd380Sjfb8856606 * mode, the programming of the entries in the TCAMs must be in
1004*2d9fd380Sjfb8856606 * reversed order - the TCAM entry of the rightmost TCAM should
1005*2d9fd380Sjfb8856606 * be programmed first; the TCAM entry of the leftmost TCAM
1006*2d9fd380Sjfb8856606 * should be programmed last.
1007*2d9fd380Sjfb8856606 */
1008*2d9fd380Sjfb8856606 offset = num_cscd - i - 1;
1009*2d9fd380Sjfb8856606 ice_memcpy(&buf.entry_key.val,
1010*2d9fd380Sjfb8856606 &keys[offset * sizeof(buf.entry_key.val)],
1011*2d9fd380Sjfb8856606 sizeof(buf.entry_key.val), ICE_NONDMA_TO_NONDMA);
1012*2d9fd380Sjfb8856606 ice_memcpy(&buf.entry_key_invert.val,
1013*2d9fd380Sjfb8856606 &inverts[offset * sizeof(buf.entry_key_invert.val)],
1014*2d9fd380Sjfb8856606 sizeof(buf.entry_key_invert.val),
1015*2d9fd380Sjfb8856606 ICE_NONDMA_TO_NONDMA);
1016*2d9fd380Sjfb8856606 status = ice_aq_program_acl_entry(hw, entry_tcam + offset, idx,
1017*2d9fd380Sjfb8856606 &buf, NULL);
1018*2d9fd380Sjfb8856606 if (status) {
1019*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "aq program acl entry failed status: %d\n",
1020*2d9fd380Sjfb8856606 status);
1021*2d9fd380Sjfb8856606 goto out;
1022*2d9fd380Sjfb8856606 }
1023*2d9fd380Sjfb8856606 }
1024*2d9fd380Sjfb8856606
1025*2d9fd380Sjfb8856606 /* Program the action memory */
1026*2d9fd380Sjfb8856606 status = ice_acl_prog_act(hw, scen, acts, acts_cnt, *entry_idx);
1027*2d9fd380Sjfb8856606
1028*2d9fd380Sjfb8856606 out:
1029*2d9fd380Sjfb8856606 if (status) {
1030*2d9fd380Sjfb8856606 ice_acl_rem_entry(hw, scen, *entry_idx);
1031*2d9fd380Sjfb8856606 *entry_idx = 0;
1032*2d9fd380Sjfb8856606 }
1033*2d9fd380Sjfb8856606
1034*2d9fd380Sjfb8856606 return status;
1035*2d9fd380Sjfb8856606 }
1036*2d9fd380Sjfb8856606
1037*2d9fd380Sjfb8856606 /**
1038*2d9fd380Sjfb8856606 * ice_acl_prog_act - Program a scenario's action memory
1039*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
1040*2d9fd380Sjfb8856606 * @scen: scenario to add the entry to
1041*2d9fd380Sjfb8856606 * @acts: pointer to a buffer containing formatted actions
1042*2d9fd380Sjfb8856606 * @acts_cnt: indicates the number of actions stored in "acts"
1043*2d9fd380Sjfb8856606 * @entry_idx: scenario relative index of the added flow entry
1044*2d9fd380Sjfb8856606 *
1045*2d9fd380Sjfb8856606 * Program a scenario's action memory
1046*2d9fd380Sjfb8856606 */
1047*2d9fd380Sjfb8856606 enum ice_status
ice_acl_prog_act(struct ice_hw * hw,struct ice_acl_scen * scen,struct ice_acl_act_entry * acts,u8 acts_cnt,u16 entry_idx)1048*2d9fd380Sjfb8856606 ice_acl_prog_act(struct ice_hw *hw, struct ice_acl_scen *scen,
1049*2d9fd380Sjfb8856606 struct ice_acl_act_entry *acts, u8 acts_cnt,
1050*2d9fd380Sjfb8856606 u16 entry_idx)
1051*2d9fd380Sjfb8856606 {
1052*2d9fd380Sjfb8856606 u8 entry_tcam, num_cscd, i, actx_idx = 0;
1053*2d9fd380Sjfb8856606 struct ice_aqc_actpair act_buf;
1054*2d9fd380Sjfb8856606 enum ice_status status = ICE_SUCCESS;
1055*2d9fd380Sjfb8856606 u16 idx;
1056*2d9fd380Sjfb8856606
1057*2d9fd380Sjfb8856606 if (entry_idx >= scen->num_entry)
1058*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
1059*2d9fd380Sjfb8856606
1060*2d9fd380Sjfb8856606 ice_memset(&act_buf, 0, sizeof(act_buf), ICE_NONDMA_MEM);
1061*2d9fd380Sjfb8856606
1062*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAMs */
1063*2d9fd380Sjfb8856606 num_cscd = DIVIDE_AND_ROUND_UP(scen->width,
1064*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
1065*2d9fd380Sjfb8856606
1066*2d9fd380Sjfb8856606 entry_tcam = ICE_ACL_TBL_TCAM_IDX(scen->start);
1067*2d9fd380Sjfb8856606 idx = ICE_ACL_TBL_TCAM_ENTRY_IDX(scen->start + entry_idx);
1068*2d9fd380Sjfb8856606
1069*2d9fd380Sjfb8856606 ice_for_each_set_bit(i, scen->act_mem_bitmap,
1070*2d9fd380Sjfb8856606 ICE_AQC_MAX_ACTION_MEMORIES) {
1071*2d9fd380Sjfb8856606 struct ice_acl_act_mem *mem = &hw->acl_tbl->act_mems[i];
1072*2d9fd380Sjfb8856606
1073*2d9fd380Sjfb8856606 if (actx_idx >= acts_cnt)
1074*2d9fd380Sjfb8856606 break;
1075*2d9fd380Sjfb8856606 if (mem->member_of_tcam >= entry_tcam &&
1076*2d9fd380Sjfb8856606 mem->member_of_tcam < entry_tcam + num_cscd) {
1077*2d9fd380Sjfb8856606 ice_memcpy(&act_buf.act[0], &acts[actx_idx],
1078*2d9fd380Sjfb8856606 sizeof(struct ice_acl_act_entry),
1079*2d9fd380Sjfb8856606 ICE_NONDMA_TO_NONDMA);
1080*2d9fd380Sjfb8856606
1081*2d9fd380Sjfb8856606 if (++actx_idx < acts_cnt) {
1082*2d9fd380Sjfb8856606 ice_memcpy(&act_buf.act[1], &acts[actx_idx],
1083*2d9fd380Sjfb8856606 sizeof(struct ice_acl_act_entry),
1084*2d9fd380Sjfb8856606 ICE_NONDMA_TO_NONDMA);
1085*2d9fd380Sjfb8856606 }
1086*2d9fd380Sjfb8856606
1087*2d9fd380Sjfb8856606 status = ice_aq_program_actpair(hw, i, idx, &act_buf,
1088*2d9fd380Sjfb8856606 NULL);
1089*2d9fd380Sjfb8856606 if (status) {
1090*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "program actpair failed status: %d\n",
1091*2d9fd380Sjfb8856606 status);
1092*2d9fd380Sjfb8856606 break;
1093*2d9fd380Sjfb8856606 }
1094*2d9fd380Sjfb8856606 actx_idx++;
1095*2d9fd380Sjfb8856606 }
1096*2d9fd380Sjfb8856606 }
1097*2d9fd380Sjfb8856606
1098*2d9fd380Sjfb8856606 if (!status && actx_idx < acts_cnt)
1099*2d9fd380Sjfb8856606 status = ICE_ERR_MAX_LIMIT;
1100*2d9fd380Sjfb8856606
1101*2d9fd380Sjfb8856606 return status;
1102*2d9fd380Sjfb8856606 }
1103*2d9fd380Sjfb8856606
1104*2d9fd380Sjfb8856606 /**
1105*2d9fd380Sjfb8856606 * ice_acl_rem_entry - Remove a flow entry from an ACL scenario
1106*2d9fd380Sjfb8856606 * @hw: pointer to the HW struct
1107*2d9fd380Sjfb8856606 * @scen: scenario to remove the entry from
1108*2d9fd380Sjfb8856606 * @entry_idx: the scenario-relative index of the flow entry being removed
1109*2d9fd380Sjfb8856606 */
1110*2d9fd380Sjfb8856606 enum ice_status
ice_acl_rem_entry(struct ice_hw * hw,struct ice_acl_scen * scen,u16 entry_idx)1111*2d9fd380Sjfb8856606 ice_acl_rem_entry(struct ice_hw *hw, struct ice_acl_scen *scen, u16 entry_idx)
1112*2d9fd380Sjfb8856606 {
1113*2d9fd380Sjfb8856606 struct ice_aqc_actpair act_buf;
1114*2d9fd380Sjfb8856606 struct ice_aqc_acl_data buf;
1115*2d9fd380Sjfb8856606 u8 entry_tcam, num_cscd, i;
1116*2d9fd380Sjfb8856606 enum ice_status status = ICE_SUCCESS;
1117*2d9fd380Sjfb8856606 u16 idx;
1118*2d9fd380Sjfb8856606
1119*2d9fd380Sjfb8856606 if (!scen)
1120*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
1121*2d9fd380Sjfb8856606
1122*2d9fd380Sjfb8856606 if (entry_idx >= scen->num_entry)
1123*2d9fd380Sjfb8856606 return ICE_ERR_MAX_LIMIT;
1124*2d9fd380Sjfb8856606
1125*2d9fd380Sjfb8856606 if (!ice_is_bit_set(scen->entry_bitmap, entry_idx))
1126*2d9fd380Sjfb8856606 return ICE_ERR_DOES_NOT_EXIST;
1127*2d9fd380Sjfb8856606
1128*2d9fd380Sjfb8856606 /* Determine number of cascaded TCAMs */
1129*2d9fd380Sjfb8856606 num_cscd = DIVIDE_AND_ROUND_UP(scen->width,
1130*2d9fd380Sjfb8856606 ICE_AQC_ACL_KEY_WIDTH_BYTES);
1131*2d9fd380Sjfb8856606
1132*2d9fd380Sjfb8856606 entry_tcam = ICE_ACL_TBL_TCAM_IDX(scen->start);
1133*2d9fd380Sjfb8856606 idx = ICE_ACL_TBL_TCAM_ENTRY_IDX(scen->start + entry_idx);
1134*2d9fd380Sjfb8856606
1135*2d9fd380Sjfb8856606 /* invalidate the flow entry */
1136*2d9fd380Sjfb8856606 ice_memset(&buf, 0, sizeof(buf), ICE_NONDMA_MEM);
1137*2d9fd380Sjfb8856606 for (i = 0; i < num_cscd; i++) {
1138*2d9fd380Sjfb8856606 status = ice_aq_program_acl_entry(hw, entry_tcam + i, idx, &buf,
1139*2d9fd380Sjfb8856606 NULL);
1140*2d9fd380Sjfb8856606 if (status)
1141*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "AQ program ACL entry failed status: %d\n",
1142*2d9fd380Sjfb8856606 status);
1143*2d9fd380Sjfb8856606 }
1144*2d9fd380Sjfb8856606
1145*2d9fd380Sjfb8856606 ice_memset(&act_buf, 0, sizeof(act_buf), ICE_NONDMA_MEM);
1146*2d9fd380Sjfb8856606
1147*2d9fd380Sjfb8856606 ice_for_each_set_bit(i, scen->act_mem_bitmap,
1148*2d9fd380Sjfb8856606 ICE_AQC_MAX_ACTION_MEMORIES) {
1149*2d9fd380Sjfb8856606 struct ice_acl_act_mem *mem = &hw->acl_tbl->act_mems[i];
1150*2d9fd380Sjfb8856606
1151*2d9fd380Sjfb8856606 if (mem->member_of_tcam >= entry_tcam &&
1152*2d9fd380Sjfb8856606 mem->member_of_tcam < entry_tcam + num_cscd) {
1153*2d9fd380Sjfb8856606 /* Invalidate allocated action pairs */
1154*2d9fd380Sjfb8856606 status = ice_aq_program_actpair(hw, i, idx, &act_buf,
1155*2d9fd380Sjfb8856606 NULL);
1156*2d9fd380Sjfb8856606 if (status)
1157*2d9fd380Sjfb8856606 ice_debug(hw, ICE_DBG_ACL, "program actpair failed status: %d\n",
1158*2d9fd380Sjfb8856606 status);
1159*2d9fd380Sjfb8856606 }
1160*2d9fd380Sjfb8856606 }
1161*2d9fd380Sjfb8856606
1162*2d9fd380Sjfb8856606 ice_acl_scen_free_entry_idx(scen, entry_idx);
1163*2d9fd380Sjfb8856606
1164*2d9fd380Sjfb8856606 return status;
1165*2d9fd380Sjfb8856606 }
1166