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