1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
4 /* Access Control List (ACL) structure:
6 * There are multiple groups of registers involved in ACL configuration:
8 * - Matching Rules: These registers define the criteria for matching incoming
9 * packets based on their header information (Layer 2 MAC, Layer 3 IP, or
10 * Layer 4 TCP/UDP). Different register settings are used depending on the
11 * matching rule mode (MD) and the Enable (ENB) settings.
13 * - Action Rules: These registers define how the ACL should modify the packet's
14 * priority, VLAN tag priority, and forwarding map once a matching rule has
15 * been triggered. The settings vary depending on whether the matching rule is
16 * in Count Mode (MD = 01 and ENB = 00) or not.
18 * - Processing Rules: These registers control the overall behavior of the ACL,
19 * such as selecting which matching rule to apply first, enabling/disabling
20 * specific rules, or specifying actions for matched packets.
23 * +----------------------+
24 * +----------------------+ | (optional) |
25 * | Matching Rules | | Matching Rules |
26 * | (Layer 2, 3, 4) | | (Layer 2, 3, 4) |
27 * +----------------------+ +----------------------+
29 * \___________________________/
31 * +----------------------+
32 * | Processing Rules |
34 * | matching rule set) |
35 * +----------------------+
38 * +----------------------+
40 * | (Modify Priority, |
43 * +----------------------+
46 #include <linux/bitops.h>
49 #include "ksz9477_reg.h"
50 #include "ksz_common.h"
52 #define KSZ9477_PORT_ACL_0 0x600
54 enum ksz9477_acl_port_access
{
55 KSZ9477_ACL_PORT_ACCESS_0
= 0x00,
56 KSZ9477_ACL_PORT_ACCESS_1
= 0x01,
57 KSZ9477_ACL_PORT_ACCESS_2
= 0x02,
58 KSZ9477_ACL_PORT_ACCESS_3
= 0x03,
59 KSZ9477_ACL_PORT_ACCESS_4
= 0x04,
60 KSZ9477_ACL_PORT_ACCESS_5
= 0x05,
61 KSZ9477_ACL_PORT_ACCESS_6
= 0x06,
62 KSZ9477_ACL_PORT_ACCESS_7
= 0x07,
63 KSZ9477_ACL_PORT_ACCESS_8
= 0x08,
64 KSZ9477_ACL_PORT_ACCESS_9
= 0x09,
65 KSZ9477_ACL_PORT_ACCESS_A
= 0x0A,
66 KSZ9477_ACL_PORT_ACCESS_B
= 0x0B,
67 KSZ9477_ACL_PORT_ACCESS_C
= 0x0C,
68 KSZ9477_ACL_PORT_ACCESS_D
= 0x0D,
69 KSZ9477_ACL_PORT_ACCESS_E
= 0x0E,
70 KSZ9477_ACL_PORT_ACCESS_F
= 0x0F,
71 KSZ9477_ACL_PORT_ACCESS_10
= 0x10,
72 KSZ9477_ACL_PORT_ACCESS_11
= 0x11
75 #define KSZ9477_ACL_MD_MASK GENMASK(5, 4)
76 #define KSZ9477_ACL_MD_DISABLE 0
77 #define KSZ9477_ACL_MD_L2_MAC 1
78 #define KSZ9477_ACL_MD_L3_IP 2
79 #define KSZ9477_ACL_MD_L4_TCP_UDP 3
81 #define KSZ9477_ACL_ENB_MASK GENMASK(3, 2)
82 #define KSZ9477_ACL_ENB_L2_COUNTER 0
83 #define KSZ9477_ACL_ENB_L2_TYPE 1
84 #define KSZ9477_ACL_ENB_L2_MAC 2
85 #define KSZ9477_ACL_ENB_L2_MAC_TYPE 3
87 /* only IPv4 src or dst can be used with mask */
88 #define KSZ9477_ACL_ENB_L3_IPV4_ADDR_MASK 1
89 /* only IPv4 src and dst can be used without mask */
90 #define KSZ9477_ACL_ENB_L3_IPV4_ADDR_SRC_DST 2
92 #define KSZ9477_ACL_ENB_L4_IP_PROTO 0
93 #define KSZ9477_ACL_ENB_L4_TCP_SRC_DST_PORT 1
94 #define KSZ9477_ACL_ENB_L4_UDP_SRC_DST_PORT 2
95 #define KSZ9477_ACL_ENB_L4_TCP_SEQ_NUMBER 3
97 #define KSZ9477_ACL_SD_SRC BIT(1)
98 #define KSZ9477_ACL_SD_DST 0
99 #define KSZ9477_ACL_EQ_EQUAL BIT(0)
100 #define KSZ9477_ACL_EQ_NOT_EQUAL 0
102 #define KSZ9477_ACL_PM_M GENMASK(7, 6)
103 #define KSZ9477_ACL_PM_DISABLE 0
104 #define KSZ9477_ACL_PM_HIGHER 1
105 #define KSZ9477_ACL_PM_LOWER 2
106 #define KSZ9477_ACL_PM_REPLACE 3
107 #define KSZ9477_ACL_P_M GENMASK(5, 3)
109 #define KSZ9477_PORT_ACL_CTRL_0 0x0612
111 #define KSZ9477_ACL_WRITE_DONE BIT(6)
112 #define KSZ9477_ACL_READ_DONE BIT(5)
113 #define KSZ9477_ACL_WRITE BIT(4)
114 #define KSZ9477_ACL_INDEX_M GENMASK(3, 0)
117 * ksz9477_dump_acl_index - Print the ACL entry at the specified index
119 * @dev: Pointer to the ksz9477 device structure.
120 * @acle: Pointer to the ACL entry array.
121 * @index: The index of the ACL entry to print.
123 * This function prints the details of an ACL entry, located at a particular
124 * index within the ksz9477 device's ACL table. It omits printing entries that
127 * Return: 1 if the entry is non-empty and printed, 0 otherwise.
129 static int ksz9477_dump_acl_index(struct ksz_device
*dev
,
130 struct ksz9477_acl_entry
*acle
, int index
)
137 entry
= &acle
[index
].entry
[0];
138 for (i
= 0; i
<= KSZ9477_ACL_PORT_ACCESS_11
; i
++) {
142 sprintf(buf
+ (i
* 3), "%02x ", entry
[i
]);
145 /* no need to print empty entries */
149 dev_err(dev
->dev
, " Entry %02d, prio: %02d : %s", index
,
150 acle
[index
].prio
, buf
);
156 * ksz9477_dump_acl - Print ACL entries
158 * @dev: Pointer to the device structure.
159 * @acle: Pointer to the ACL entry array.
161 static void ksz9477_dump_acl(struct ksz_device
*dev
,
162 struct ksz9477_acl_entry
*acle
)
167 for (i
= 0; i
< KSZ9477_ACL_MAX_ENTRIES
; i
++)
168 count
+= ksz9477_dump_acl_index(dev
, acle
, i
);
170 if (count
!= KSZ9477_ACL_MAX_ENTRIES
- 1)
171 dev_err(dev
->dev
, " Empty ACL entries were skipped\n");
175 * ksz9477_acl_is_valid_matching_rule - Check if an ACL entry contains a valid
178 * @entry: Pointer to ACL entry buffer
180 * This function checks if the given ACL entry buffer contains a valid
181 * matching rule by inspecting the Mode (MD) and Enable (ENB) fields.
183 * Returns: True if it's a valid matching rule, false otherwise.
185 static bool ksz9477_acl_is_valid_matching_rule(u8
*entry
)
189 val1
= entry
[KSZ9477_ACL_PORT_ACCESS_1
];
191 md
= FIELD_GET(KSZ9477_ACL_MD_MASK
, val1
);
192 if (md
== KSZ9477_ACL_MD_DISABLE
)
195 if (md
== KSZ9477_ACL_MD_L2_MAC
) {
196 /* L2 counter is not support, so it is not valid rule for now */
197 enb
= FIELD_GET(KSZ9477_ACL_ENB_MASK
, val1
);
198 if (enb
== KSZ9477_ACL_ENB_L2_COUNTER
)
206 * ksz9477_acl_get_cont_entr - Get count of contiguous ACL entries and validate
207 * the matching rules.
208 * @dev: Pointer to the KSZ9477 device structure.
209 * @port: Port number.
210 * @index: Index of the starting ACL entry.
212 * Based on the KSZ9477 switch's Access Control List (ACL) system, the RuleSet
213 * in an ACL entry indicates which entries contain Matching rules linked to it.
214 * This RuleSet is represented by two registers: KSZ9477_ACL_PORT_ACCESS_E and
215 * KSZ9477_ACL_PORT_ACCESS_F. Each bit set in these registers corresponds to
216 * an entry containing a Matching rule for this RuleSet.
218 * For a single Matching rule linked, only one bit is set. However, when an
219 * entry links multiple Matching rules, forming what's termed a 'complex rule',
220 * multiple bits are set in these registers.
222 * This function checks that, for complex rules, the entries containing the
223 * linked Matching rules are contiguous in terms of their indices. It calculates
224 * and returns the number of these contiguous entries.
227 * - 0 if the entry is empty and can be safely overwritten
228 * - 1 if the entry represents a simple rule
229 * - The number of contiguous entries if it is the root entry of a complex
231 * - -ENOTEMPTY if the entry is part of a complex rule but not the root
233 * - -EINVAL if the validation fails
235 static int ksz9477_acl_get_cont_entr(struct ksz_device
*dev
, int port
,
238 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
239 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
240 int start_idx
, end_idx
, contiguous_count
;
246 entry
= &acles
->entries
[index
].entry
[0];
247 vale
= entry
[KSZ9477_ACL_PORT_ACCESS_E
];
248 valf
= entry
[KSZ9477_ACL_PORT_ACCESS_F
];
250 val
= (vale
<< 8) | valf
;
252 /* If no bits are set, return an appropriate value or error */
254 if (ksz9477_acl_is_valid_matching_rule(entry
)) {
255 /* Looks like we are about to corrupt some complex rule.
256 * Do not print an error here, as this is a normal case
257 * when we are trying to find a free or starting entry.
259 dev_dbg(dev
->dev
, "ACL: entry %d starting with a valid matching rule, but no bits set in RuleSet\n",
264 /* This entry does not contain a valid matching rule */
268 start_idx
= find_first_bit((unsigned long *)&val
, 16);
269 end_idx
= find_last_bit((unsigned long *)&val
, 16);
271 /* Calculate the contiguous count */
272 contiguous_count
= end_idx
- start_idx
+ 1;
274 /* Check if the number of bits set in val matches our calculated count */
275 if (contiguous_count
!= hweight16(val
)) {
276 /* Probably we have a fragmented complex rule, which is not
277 * supported by this driver.
279 dev_err(dev
->dev
, "ACL: number of bits set in RuleSet does not match calculated count\n");
283 /* loop over the contiguous entries and check for valid matching rules */
284 for (i
= start_idx
; i
<= end_idx
; i
++) {
285 u8
*current_entry
= &acles
->entries
[i
].entry
[0];
287 if (!ksz9477_acl_is_valid_matching_rule(current_entry
)) {
288 /* we have something linked without a valid matching
291 dev_err(dev
->dev
, "ACL: entry %d does not contain a valid matching rule\n",
297 vale
= current_entry
[KSZ9477_ACL_PORT_ACCESS_E
];
298 valf
= current_entry
[KSZ9477_ACL_PORT_ACCESS_F
];
299 /* Following entry should have empty linkage list */
301 dev_err(dev
->dev
, "ACL: entry %d has non-empty RuleSet linkage\n",
308 return contiguous_count
;
312 * ksz9477_acl_update_linkage - Update the RuleSet linkage for an ACL entry
313 * after a move operation.
315 * @dev: Pointer to the ksz_device.
316 * @entry: Pointer to the ACL entry array.
317 * @old_idx: The original index of the ACL entry before moving.
318 * @new_idx: The new index of the ACL entry after moving.
320 * This function updates the RuleSet linkage bits for an ACL entry when
321 * it's moved from one position to another in the ACL table. The RuleSet
322 * linkage is represented by two 8-bit registers, which are combined
323 * into a 16-bit value for easier manipulation. The linkage bits are shifted
324 * based on the difference between the old and new index. If any bits are lost
325 * during the shift operation, an error is returned.
327 * Note: Fragmentation within a RuleSet is not supported. Hence, entries must
328 * be moved as complete blocks, maintaining the integrity of the RuleSet.
330 * Returns: 0 on success, or -EINVAL if any RuleSet linkage bits are lost
333 static int ksz9477_acl_update_linkage(struct ksz_device
*dev
, u8
*entry
,
334 u16 old_idx
, u16 new_idx
)
336 unsigned int original_bit_count
;
337 unsigned long rule_linkage
;
341 val0
= entry
[KSZ9477_ACL_PORT_ACCESS_0
];
342 vale
= entry
[KSZ9477_ACL_PORT_ACCESS_E
];
343 valf
= entry
[KSZ9477_ACL_PORT_ACCESS_F
];
345 /* Combine the two u8 values into one u16 for easier manipulation */
346 rule_linkage
= (vale
<< 8) | valf
;
347 original_bit_count
= hweight16(rule_linkage
);
349 /* Even if HW is able to handle fragmented RuleSet, we don't support it.
350 * RuleSet is filled only for the first entry of the set.
355 if (val0
!= old_idx
) {
356 dev_err(dev
->dev
, "ACL: entry %d has unexpected ActionRule linkage: %d\n",
363 /* Calculate the number of positions to shift */
364 shift
= new_idx
- old_idx
;
366 /* Shift the RuleSet */
368 rule_linkage
<<= shift
;
370 rule_linkage
>>= -shift
;
372 /* Check that no bits were lost in the process */
373 if (original_bit_count
!= hweight16(rule_linkage
)) {
374 dev_err(dev
->dev
, "ACL RuleSet linkage bits lost during move\n");
378 entry
[KSZ9477_ACL_PORT_ACCESS_0
] = val0
;
380 /* Update the RuleSet bitfields in the entry */
381 entry
[KSZ9477_ACL_PORT_ACCESS_E
] = (rule_linkage
>> 8) & 0xFF;
382 entry
[KSZ9477_ACL_PORT_ACCESS_F
] = rule_linkage
& 0xFF;
388 * ksz9477_validate_and_get_src_count - Validate source and destination indices
389 * and determine the source entry count.
390 * @dev: Pointer to the KSZ device structure.
391 * @port: Port number on the KSZ device where the ACL entries reside.
392 * @src_idx: Index of the starting ACL entry that needs to be validated.
393 * @dst_idx: Index of the destination where the source entries are intended to
395 * @src_count: Pointer to the variable that will hold the number of contiguous
396 * source entries if the validation passes.
397 * @dst_count: Pointer to the variable that will hold the number of contiguous
398 * destination entries if the validation passes.
400 * This function performs validation on the source and destination indices
401 * provided for ACL entries. It checks if the indices are within the valid
402 * range, and if the source entries are contiguous. Additionally, the function
403 * ensures that there's adequate space at the destination for the source entries
404 * and that the destination index isn't in the middle of a RuleSet. If all
405 * validations pass, the function returns the number of contiguous source and
406 * destination entries.
408 * Return: 0 on success, otherwise returns a negative error code if any
409 * validation check fails.
411 static int ksz9477_validate_and_get_src_count(struct ksz_device
*dev
, int port
,
412 int src_idx
, int dst_idx
,
413 int *src_count
, int *dst_count
)
417 if (src_idx
>= KSZ9477_ACL_MAX_ENTRIES
||
418 dst_idx
>= KSZ9477_ACL_MAX_ENTRIES
) {
419 dev_err(dev
->dev
, "ACL: invalid entry index\n");
423 /* Validate if the source entries are contiguous */
424 ret
= ksz9477_acl_get_cont_entr(dev
, port
, src_idx
);
430 dev_err(dev
->dev
, "ACL: source entry is empty\n");
434 if (dst_idx
+ *src_count
>= KSZ9477_ACL_MAX_ENTRIES
) {
435 dev_err(dev
->dev
, "ACL: Not enough space at the destination. Move operation will fail.\n");
439 /* Validate if the destination entry is empty or not in the middle of
442 ret
= ksz9477_acl_get_cont_entr(dev
, port
, dst_idx
);
451 * ksz9477_move_entries_downwards - Move a range of ACL entries downwards in
453 * @dev: Pointer to the KSZ device structure.
454 * @acles: Pointer to the structure encapsulating all the ACL entries.
455 * @start_idx: Starting index of the entries to be relocated.
456 * @num_entries_to_move: Number of consecutive entries to be relocated.
457 * @end_idx: Destination index where the first entry should be situated post
460 * This function is responsible for rearranging a specific block of ACL entries
461 * by shifting them downwards in the list based on the supplied source and
462 * destination indices. It ensures that the linkage between the ACL entries is
463 * maintained accurately after the relocation.
465 * Return: 0 on successful relocation of entries, otherwise returns a negative
468 static int ksz9477_move_entries_downwards(struct ksz_device
*dev
,
469 struct ksz9477_acl_entries
*acles
,
471 u16 num_entries_to_move
,
474 struct ksz9477_acl_entry
*e
;
477 for (i
= start_idx
; i
< end_idx
; i
++) {
478 e
= &acles
->entries
[i
];
479 *e
= acles
->entries
[i
+ num_entries_to_move
];
481 ret
= ksz9477_acl_update_linkage(dev
, &e
->entry
[0],
482 i
+ num_entries_to_move
, i
);
491 * ksz9477_move_entries_upwards - Move a range of ACL entries upwards in the
493 * @dev: Pointer to the KSZ device structure.
494 * @acles: Pointer to the structure holding all the ACL entries.
495 * @start_idx: The starting index of the entries to be moved.
496 * @num_entries_to_move: Number of contiguous entries to be moved.
497 * @target_idx: The destination index where the first entry should be placed
500 * This function rearranges a chunk of ACL entries by moving them upwards
501 * in the list based on the given source and destination indices. The reordering
502 * process preserves the linkage between entries by updating it accordingly.
504 * Return: 0 if the entries were successfully moved, otherwise a negative error
507 static int ksz9477_move_entries_upwards(struct ksz_device
*dev
,
508 struct ksz9477_acl_entries
*acles
,
509 u16 start_idx
, u16 num_entries_to_move
,
512 struct ksz9477_acl_entry
*e
;
515 for (i
= start_idx
; i
> target_idx
; i
--) {
516 b
= i
+ num_entries_to_move
- 1;
518 e
= &acles
->entries
[b
];
519 *e
= acles
->entries
[i
- 1];
521 ret
= ksz9477_acl_update_linkage(dev
, &e
->entry
[0], i
- 1, b
);
530 * ksz9477_acl_move_entries - Move a block of contiguous ACL entries from a
531 * source to a destination index.
532 * @dev: Pointer to the KSZ9477 device structure.
533 * @port: Port number.
534 * @src_idx: Index of the starting source ACL entry.
535 * @dst_idx: Index of the starting destination ACL entry.
537 * This function aims to move a block of contiguous ACL entries from the source
538 * index to the destination index while ensuring the integrity and validity of
541 * In case of any errors during the adjustments or copying, the function will
542 * restore the ACL entries to their original state from the backup.
544 * Return: 0 if the move operation is successful. Returns -EINVAL for validation
545 * errors or other error codes based on specific failure conditions.
547 static int ksz9477_acl_move_entries(struct ksz_device
*dev
, int port
,
548 u16 src_idx
, u16 dst_idx
)
550 struct ksz9477_acl_entry buffer
[KSZ9477_ACL_MAX_ENTRIES
];
551 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
552 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
553 int src_count
, ret
, dst_count
;
556 if (src_idx
== dst_idx
)
559 ret
= ksz9477_validate_and_get_src_count(dev
, port
, src_idx
, dst_idx
,
560 &src_count
, &dst_count
);
564 /* In case dst_index is greater than src_index, we need to adjust the
565 * destination index to account for the entries that will be moved
566 * downwards and the size of the entry located at dst_idx.
568 if (dst_idx
> src_idx
)
569 dst_idx
= dst_idx
+ dst_count
- src_count
;
571 /* Copy source block to buffer and update its linkage */
572 for (int i
= 0; i
< src_count
; i
++) {
573 buffer
[i
] = acles
->entries
[src_idx
+ i
];
574 ret
= ksz9477_acl_update_linkage(dev
, &buffer
[i
].entry
[0],
575 src_idx
+ i
, dst_idx
+ i
);
580 /* Adjust other entries and their linkage based on destination */
581 if (dst_idx
> src_idx
) {
582 ret
= ksz9477_move_entries_downwards(dev
, acles
, src_idx
,
585 ret
= ksz9477_move_entries_upwards(dev
, acles
, src_idx
,
591 /* Copy buffer to destination block */
592 for (int i
= 0; i
< src_count
; i
++)
593 acles
->entries
[dst_idx
+ i
] = buffer
[i
];
599 * ksz9477_get_next_block_start - Identify the starting index of the next ACL
601 * @dev: Pointer to the device structure.
602 * @port: The port number on which the ACL entries are being checked.
603 * @start: The starting index from which the search begins.
605 * This function looks for the next valid ACL block starting from the provided
606 * 'start' index and returns the beginning index of that block. If the block is
607 * invalid or if it reaches the end of the ACL entries without finding another
608 * block, it returns the maximum ACL entries count.
611 * - The starting index of the next valid ACL block.
612 * - KSZ9477_ACL_MAX_ENTRIES if no other valid blocks are found after 'start'.
613 * - A negative error code if an error occurs while checking.
615 static int ksz9477_get_next_block_start(struct ksz_device
*dev
, int port
,
620 for (int i
= start
; i
< KSZ9477_ACL_MAX_ENTRIES
;) {
621 block_size
= ksz9477_acl_get_cont_entr(dev
, port
, i
);
622 if (block_size
< 0 && block_size
!= -ENOTEMPTY
)
630 return KSZ9477_ACL_MAX_ENTRIES
;
634 * ksz9477_swap_acl_blocks - Swap two ACL blocks
635 * @dev: Pointer to the device structure.
636 * @port: The port number on which the ACL blocks are to be swapped.
637 * @i: The starting index of the first ACL block.
638 * @j: The starting index of the second ACL block.
640 * This function is used to swap two ACL blocks present at given indices. The
641 * main purpose is to aid in the sorting and reordering of ACL blocks based on
642 * certain criteria, e.g., priority. It checks the validity of the block at
643 * index 'i', ensuring it's not an empty block, and then proceeds to swap it
644 * with the block at index 'j'.
647 * - 0 on successful swapping of blocks.
648 * - -EINVAL if the block at index 'i' is empty.
649 * - A negative error code if any other error occurs during the swap.
651 static int ksz9477_swap_acl_blocks(struct ksz_device
*dev
, int port
, int i
,
654 int ret
, current_block_size
;
656 current_block_size
= ksz9477_acl_get_cont_entr(dev
, port
, i
);
657 if (current_block_size
< 0)
658 return current_block_size
;
660 if (!current_block_size
) {
661 dev_err(dev
->dev
, "ACL: swapping empty entry %d\n", i
);
665 ret
= ksz9477_acl_move_entries(dev
, port
, i
, j
);
669 ret
= ksz9477_acl_move_entries(dev
, port
, j
- current_block_size
, i
);
677 * ksz9477_sort_acl_entr_no_back - Sort ACL entries for a given port based on
678 * priority without backing up entries.
679 * @dev: Pointer to the device structure.
680 * @port: The port number whose ACL entries need to be sorted.
682 * This function sorts ACL entries of the specified port using a variant of the
683 * bubble sort algorithm. It operates on blocks of ACL entries rather than
684 * individual entries. Each block's starting point is identified and then
685 * compared with subsequent blocks based on their priority. If the current
686 * block has a lower priority than the subsequent block, the two blocks are
689 * This is done in order to maintain an organized order of ACL entries based on
690 * priority, ensuring efficient and predictable ACL rule application.
693 * - 0 on successful sorting of entries.
694 * - A negative error code if any issue arises during sorting, e.g.,
695 * if the function is unable to get the next block start.
697 static int ksz9477_sort_acl_entr_no_back(struct ksz_device
*dev
, int port
)
699 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
700 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
701 struct ksz9477_acl_entry
*curr
, *next
;
705 for (i
= 0; i
< KSZ9477_ACL_MAX_ENTRIES
;) {
706 curr
= &acles
->entries
[i
];
708 j
= ksz9477_get_next_block_start(dev
, port
, i
+ 1);
712 while (j
< KSZ9477_ACL_MAX_ENTRIES
) {
713 next
= &acles
->entries
[j
];
715 if (curr
->prio
> next
->prio
) {
716 ret
= ksz9477_swap_acl_blocks(dev
, port
, i
, j
);
721 j
= ksz9477_get_next_block_start(dev
, port
, j
+ 1);
726 i
= ksz9477_get_next_block_start(dev
, port
, i
+ 1);
735 * ksz9477_sort_acl_entries - Sort the ACL entries for a given port.
736 * @dev: Pointer to the KSZ device.
737 * @port: Port number.
739 * This function sorts the Access Control List (ACL) entries for a specified
740 * port. Before sorting, a backup of the original entries is created. If the
741 * sorting process fails, the function will log error messages displaying both
742 * the original and attempted sorted entries, and then restore the original
743 * entries from the backup.
745 * Return: 0 if the sorting succeeds, otherwise a negative error code.
747 int ksz9477_sort_acl_entries(struct ksz_device
*dev
, int port
)
749 struct ksz9477_acl_entry backup
[KSZ9477_ACL_MAX_ENTRIES
];
750 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
751 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
754 /* create a backup of the ACL entries, if something goes wrong
755 * we can restore the ACL entries.
757 memcpy(backup
, acles
->entries
, sizeof(backup
));
759 ret
= ksz9477_sort_acl_entr_no_back(dev
, port
);
761 dev_err(dev
->dev
, "ACL: failed to sort entries for port %d\n",
763 dev_err(dev
->dev
, "ACL dump before sorting:\n");
764 ksz9477_dump_acl(dev
, backup
);
765 dev_err(dev
->dev
, "ACL dump after sorting:\n");
766 ksz9477_dump_acl(dev
, acles
->entries
);
767 /* Restore the original entries */
768 memcpy(acles
->entries
, backup
, sizeof(backup
));
775 * ksz9477_acl_wait_ready - Waits for the ACL operation to complete on a given
777 * @dev: The ksz_device instance.
778 * @port: The port number to wait for.
780 * This function checks if the ACL write or read operation is completed by
781 * polling the specified register.
783 * Returns: 0 if the operation is successful, or a negative error code if an
786 static int ksz9477_acl_wait_ready(struct ksz_device
*dev
, int port
)
788 unsigned int wr_mask
= KSZ9477_ACL_WRITE_DONE
| KSZ9477_ACL_READ_DONE
;
789 unsigned int val
, reg
;
792 reg
= dev
->dev_ops
->get_port_addr(port
, KSZ9477_PORT_ACL_CTRL_0
);
794 ret
= regmap_read_poll_timeout(dev
->regmap
[0], reg
, val
,
795 (val
& wr_mask
) == wr_mask
, 1000, 10000);
797 dev_err(dev
->dev
, "Failed to read/write ACL table\n");
803 * ksz9477_acl_entry_write - Writes an ACL entry to a given port at the
805 * @dev: The ksz_device instance.
806 * @port: The port number to write the ACL entry to.
807 * @entry: A pointer to the ACL entry data.
808 * @idx: The index at which to write the ACL entry.
810 * This function writes the provided ACL entry to the specified port at the
813 * Returns: 0 if the operation is successful, or a negative error code if an
816 static int ksz9477_acl_entry_write(struct ksz_device
*dev
, int port
, u8
*entry
,
822 for (i
= 0; i
< KSZ9477_ACL_ENTRY_SIZE
; i
++) {
823 ret
= ksz_pwrite8(dev
, port
, KSZ9477_PORT_ACL_0
+ i
, entry
[i
]);
825 dev_err(dev
->dev
, "Failed to write ACL entry %d\n", i
);
830 /* write everything down */
831 val
= FIELD_PREP(KSZ9477_ACL_INDEX_M
, idx
) | KSZ9477_ACL_WRITE
;
832 ret
= ksz_pwrite8(dev
, port
, KSZ9477_PORT_ACL_CTRL_0
, val
);
836 /* wait until everything is written */
837 return ksz9477_acl_wait_ready(dev
, port
);
841 * ksz9477_acl_port_enable - Enables ACL functionality on a given port.
842 * @dev: The ksz_device instance.
843 * @port: The port number on which to enable ACL functionality.
845 * This function enables ACL functionality on the specified port by configuring
846 * the appropriate control registers. It returns 0 if the operation is
847 * successful, or a negative error code if an error occurs.
849 * 0xn801 - KSZ9477S 5.2.8.2 Port Priority Control Register
850 * Bit 7 - Highest Priority
851 * Bit 6 - OR'ed Priority
852 * Bit 4 - MAC Address Priority Classification
853 * Bit 3 - VLAN Priority Classification
854 * Bit 2 - 802.1p Priority Classification
855 * Bit 1 - Diffserv Priority Classification
856 * Bit 0 - ACL Priority Classification
858 * Current driver implementation sets 802.1p priority classification by default.
859 * In this function we add ACL priority classification with OR'ed priority.
860 * According to testing, priority set by ACL will supersede the 802.1p priority.
862 * 0xn803 - KSZ9477S 5.2.8.4 Port Authentication Control Register
863 * Bit 2 - Access Control List (ACL) Enable
864 * Bits 1:0 - Authentication Mode
866 * 01 = Block Mode. Authentication is enabled. When ACL is
867 * enabled, all traffic that misses the ACL rules is
868 * blocked; otherwise ACL actions apply.
869 * 10 = Pass Mode. Authentication is disabled. When ACL is
870 * enabled, all traffic that misses the ACL rules is
871 * forwarded; otherwise ACL actions apply.
872 * 11 = Trap Mode. Authentication is enabled. All traffic is
873 * forwarded to the host port. When ACL is enabled, all
874 * traffic that misses the ACL rules is blocked; otherwise
877 * We are using Pass Mode int this function.
879 * Returns: 0 if the operation is successful, or a negative error code if an
882 static int ksz9477_acl_port_enable(struct ksz_device
*dev
, int port
)
886 ret
= ksz_prmw8(dev
, port
, P_PRIO_CTRL
, 0, PORT_ACL_PRIO_ENABLE
|
891 return ksz_pwrite8(dev
, port
, REG_PORT_MRI_AUTHEN_CTRL
,
893 FIELD_PREP(PORT_AUTHEN_MODE
, PORT_AUTHEN_PASS
));
897 * ksz9477_acl_port_disable - Disables ACL functionality on a given port.
898 * @dev: The ksz_device instance.
899 * @port: The port number on which to disable ACL functionality.
901 * This function disables ACL functionality on the specified port by writing a
902 * value of 0 to the REG_PORT_MRI_AUTHEN_CTRL control register and remove
903 * PORT_ACL_PRIO_ENABLE bit from P_PRIO_CTRL register.
905 * Returns: 0 if the operation is successful, or a negative error code if an
908 static int ksz9477_acl_port_disable(struct ksz_device
*dev
, int port
)
912 ret
= ksz_prmw8(dev
, port
, P_PRIO_CTRL
, PORT_ACL_PRIO_ENABLE
, 0);
916 return ksz_pwrite8(dev
, port
, REG_PORT_MRI_AUTHEN_CTRL
, 0);
920 * ksz9477_acl_write_list - Write a list of ACL entries to a given port.
921 * @dev: The ksz_device instance.
922 * @port: The port number on which to write ACL entries.
924 * This function enables ACL functionality on the specified port, writes a list
925 * of ACL entries to the port, and disables ACL functionality if there are no
928 * Returns: 0 if the operation is successful, or a negative error code if an
931 int ksz9477_acl_write_list(struct ksz_device
*dev
, int port
)
933 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
934 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
937 /* ACL should be enabled before writing entries */
938 ret
= ksz9477_acl_port_enable(dev
, port
);
942 /* write all entries */
943 for (i
= 0; i
< ARRAY_SIZE(acles
->entries
); i
++) {
944 u8
*entry
= acles
->entries
[i
].entry
;
946 /* Check if entry was removed and should be zeroed.
947 * If last fields of the entry are not zero, it means
948 * it is removed locally but currently not synced with the HW.
949 * So, we will write it down to the HW to remove it.
951 if (i
>= acles
->entries_count
&&
952 entry
[KSZ9477_ACL_PORT_ACCESS_10
] == 0 &&
953 entry
[KSZ9477_ACL_PORT_ACCESS_11
] == 0)
956 ret
= ksz9477_acl_entry_write(dev
, port
, entry
, i
);
960 /* now removed entry is clean on HW side, so it can
963 if (i
>= acles
->entries_count
&&
964 entry
[KSZ9477_ACL_PORT_ACCESS_10
] != 0 &&
965 entry
[KSZ9477_ACL_PORT_ACCESS_11
] != 0) {
966 entry
[KSZ9477_ACL_PORT_ACCESS_10
] = 0;
967 entry
[KSZ9477_ACL_PORT_ACCESS_11
] = 0;
971 if (!acles
->entries_count
)
972 return ksz9477_acl_port_disable(dev
, port
);
978 * ksz9477_acl_remove_entries - Remove ACL entries with a given cookie from a
979 * specified ksz9477_acl_entries structure.
980 * @dev: The ksz_device instance.
981 * @port: The port number on which to remove ACL entries.
982 * @acles: The ksz9477_acl_entries instance.
983 * @cookie: The cookie value to match for entry removal.
985 * This function iterates through the entries array, removing any entries with
986 * a matching cookie value. The remaining entries are then shifted down to fill
989 void ksz9477_acl_remove_entries(struct ksz_device
*dev
, int port
,
990 struct ksz9477_acl_entries
*acles
,
991 unsigned long cookie
)
993 int entries_count
= acles
->entries_count
;
994 int ret
, i
, src_count
;
1000 /* Search for the first position with the cookie */
1001 for (i
= 0; i
< entries_count
; i
++) {
1002 if (acles
->entries
[i
].cookie
== cookie
) {
1008 /* No entries with the matching cookie found */
1012 /* Get the size of the cookie entry. We may have complex entries. */
1013 src_count
= ksz9477_acl_get_cont_entr(dev
, port
, src_idx
);
1017 /* Move all entries down to overwrite removed entry with the cookie */
1018 ret
= ksz9477_move_entries_downwards(dev
, acles
, src_idx
,
1020 entries_count
- src_count
);
1022 dev_err(dev
->dev
, "Failed to move ACL entries down\n");
1026 /* Overwrite new empty places at the end of the list with zeros to make
1027 * sure not unexpected things will happen or no unexplored quirks will
1030 for (i
= entries_count
- src_count
; i
< entries_count
; i
++) {
1031 struct ksz9477_acl_entry
*entry
= &acles
->entries
[i
];
1033 memset(entry
, 0, sizeof(*entry
));
1035 /* Set all access bits to be able to write zeroed entry to HW */
1036 entry
->entry
[KSZ9477_ACL_PORT_ACCESS_10
] = 0xff;
1037 entry
->entry
[KSZ9477_ACL_PORT_ACCESS_11
] = 0xff;
1040 /* Adjust the total entries count */
1041 acles
->entries_count
-= src_count
;
1045 * ksz9477_port_acl_init - Initialize the ACL for a specified port on a ksz
1047 * @dev: The ksz_device instance.
1048 * @port: The port number to initialize the ACL for.
1050 * This function allocates memory for an acl structure, associates it with the
1051 * specified port, and initializes the ACL entries to a default state. The
1052 * entries are then written using the ksz9477_acl_write_list function, ensuring
1053 * the ACL has a predictable initial hardware state.
1055 * Returns: 0 on success, or an error code on failure.
1057 int ksz9477_port_acl_init(struct ksz_device
*dev
, int port
)
1059 struct ksz9477_acl_entries
*acles
;
1060 struct ksz9477_acl_priv
*acl
;
1063 acl
= kzalloc(sizeof(*acl
), GFP_KERNEL
);
1067 dev
->ports
[port
].acl_priv
= acl
;
1069 acles
= &acl
->acles
;
1070 /* write all entries */
1071 for (i
= 0; i
< ARRAY_SIZE(acles
->entries
); i
++) {
1072 u8
*entry
= acles
->entries
[i
].entry
;
1074 /* Set all access bits to be able to write zeroed
1077 entry
[KSZ9477_ACL_PORT_ACCESS_10
] = 0xff;
1078 entry
[KSZ9477_ACL_PORT_ACCESS_11
] = 0xff;
1081 ret
= ksz9477_acl_write_list(dev
, port
);
1088 kfree(dev
->ports
[port
].acl_priv
);
1089 dev
->ports
[port
].acl_priv
= NULL
;
1095 * ksz9477_port_acl_free - Free the ACL resources for a specified port on a ksz
1097 * @dev: The ksz_device instance.
1098 * @port: The port number to initialize the ACL for.
1100 * This disables the ACL for the specified port and frees the associated memory,
1102 void ksz9477_port_acl_free(struct ksz_device
*dev
, int port
)
1104 if (!dev
->ports
[port
].acl_priv
)
1107 ksz9477_acl_port_disable(dev
, port
);
1109 kfree(dev
->ports
[port
].acl_priv
);
1110 dev
->ports
[port
].acl_priv
= NULL
;
1114 * ksz9477_acl_set_reg - Set entry[16] and entry[17] depending on the updated
1116 * @entry: An array containing the entries
1117 * @reg: The register of the entry that needs to be updated
1118 * @value: The value to be assigned to the updated entry
1120 * This function updates the entry[] array based on the provided register and
1121 * value. It also sets entry[0x10] and entry[0x11] according to the ACL byte
1124 * 0x10 - Byte Enable [15:8]
1126 * Each bit enables accessing one of the ACL bytes when a read or write is
1127 * initiated by writing to the Port ACL Byte Enable LSB Register.
1128 * Bit 0 applies to the Port ACL Access 7 Register
1129 * Bit 1 applies to the Port ACL Access 6 Register, etc.
1130 * Bit 7 applies to the Port ACL Access 0 Register
1131 * 1 = Byte is selected for read/write
1132 * 0 = Byte is not selected
1134 * 0x11 - Byte Enable [7:0]
1136 * Each bit enables accessing one of the ACL bytes when a read or write is
1137 * initiated by writing to the Port ACL Byte Enable LSB Register.
1138 * Bit 0 applies to the Port ACL Access F Register
1139 * Bit 1 applies to the Port ACL Access E Register, etc.
1140 * Bit 7 applies to the Port ACL Access 8 Register
1141 * 1 = Byte is selected for read/write
1142 * 0 = Byte is not selected
1144 static void ksz9477_acl_set_reg(u8
*entry
, enum ksz9477_acl_port_access reg
,
1147 if (reg
>= KSZ9477_ACL_PORT_ACCESS_0
&&
1148 reg
<= KSZ9477_ACL_PORT_ACCESS_7
) {
1149 entry
[KSZ9477_ACL_PORT_ACCESS_10
] |=
1150 BIT(KSZ9477_ACL_PORT_ACCESS_7
- reg
);
1151 } else if (reg
>= KSZ9477_ACL_PORT_ACCESS_8
&&
1152 reg
<= KSZ9477_ACL_PORT_ACCESS_F
) {
1153 entry
[KSZ9477_ACL_PORT_ACCESS_11
] |=
1154 BIT(KSZ9477_ACL_PORT_ACCESS_F
- reg
);
1164 * ksz9477_acl_matching_rule_cfg_l2 - Configure an ACL filtering entry to match
1165 * L2 types of Ethernet frames
1166 * @entry: Pointer to ACL entry buffer
1167 * @ethertype: Ethertype value
1168 * @eth_addr: Pointer to Ethernet address
1169 * @is_src: If true, match the source MAC address; if false, match the
1170 * destination MAC address
1172 * This function configures an Access Control List (ACL) filtering
1173 * entry to match Layer 2 types of Ethernet frames based on the provided
1174 * ethertype and Ethernet address. Additionally, it can match either the source
1175 * or destination MAC address depending on the value of the is_src parameter.
1177 * Register Descriptions for MD = 01 and ENB != 00 (Layer 2 MAC header
1180 * 0x01 - Mode and Enable
1181 * Bits 5:4 - MD (Mode)
1182 * 01 = Layer 2 MAC header or counter filtering
1183 * Bits 3:2 - ENB (Enable)
1184 * 01 = Comparison is performed only on the TYPE value
1185 * 10 = Comparison is performed only on the MAC Address value
1186 * 11 = Both the MAC Address and TYPE are tested
1187 * Bit 1 - S/D (Source / Destination)
1188 * 0 = Destination address
1189 * 1 = Source address
1190 * Bit 0 - EQ (Equal / Not Equal)
1191 * 0 = Not Equal produces true result
1192 * 1 = Equal produces true result
1194 * 0x02-0x07 - MAC Address
1195 * 0x02 - MAC Address [47:40]
1196 * 0x03 - MAC Address [39:32]
1197 * 0x04 - MAC Address [31:24]
1198 * 0x05 - MAC Address [23:16]
1199 * 0x06 - MAC Address [15:8]
1200 * 0x07 - MAC Address [7:0]
1202 * 0x08-0x09 - EtherType
1203 * 0x08 - EtherType [15:8]
1204 * 0x09 - EtherType [7:0]
1206 static void ksz9477_acl_matching_rule_cfg_l2(u8
*entry
, u16 ethertype
,
1207 u8
*eth_addr
, bool is_src
)
1213 enb
|= KSZ9477_ACL_ENB_L2_TYPE
;
1215 enb
|= KSZ9477_ACL_ENB_L2_MAC
;
1217 val
= FIELD_PREP(KSZ9477_ACL_MD_MASK
, KSZ9477_ACL_MD_L2_MAC
) |
1218 FIELD_PREP(KSZ9477_ACL_ENB_MASK
, enb
) |
1219 FIELD_PREP(KSZ9477_ACL_SD_SRC
, is_src
) | KSZ9477_ACL_EQ_EQUAL
;
1220 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_1
, val
);
1225 for (i
= 0; i
< ETH_ALEN
; i
++) {
1226 ksz9477_acl_set_reg(entry
,
1227 KSZ9477_ACL_PORT_ACCESS_2
+ i
,
1232 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_8
, ethertype
>> 8);
1233 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_9
, ethertype
& 0xff);
1237 * ksz9477_acl_action_rule_cfg - Set action for an ACL entry
1238 * @entry: Pointer to the ACL entry
1239 * @force_prio: If true, force the priority value
1240 * @prio_val: Priority value
1242 * This function sets the action for the specified ACL entry. It prepares
1243 * the priority mode and traffic class values and updates the entry's
1244 * action registers accordingly. Currently, there is no port or VLAN PCP
1247 * ACL Action Rule Parameters for Non-Count Modes (MD ≠ 01 or ENB ≠ 00)
1249 * 0x0A - PM, P, RPE, RP[2:1]
1250 * Bits 7:6 - PM[1:0] - Priority Mode
1251 * 00 = ACL does not specify the packet priority. Priority is
1252 * determined by standard QoS functions.
1253 * 01 = Change packet priority to P[2:0] if it is greater than QoS
1255 * 10 = Change packet priority to P[2:0] if it is smaller than the
1257 * 11 = Always change packet priority to P[2:0].
1258 * Bits 5:3 - P[2:0] - Priority value
1259 * Bit 2 - RPE - Remark Priority Enable
1260 * Bits 1:0 - RP[2:1] - Remarked Priority value (bits 2:1)
1261 * 0 = Disable priority remarking
1262 * 1 = Enable priority remarking. VLAN tag priority (PCP) bits are
1263 * replaced by RP[2:0].
1266 * Bit 7 - RP[0] - Remarked Priority value (bit 0)
1267 * Bits 6:5 - MM[1:0] - Map Mode
1268 * 00 = No forwarding remapping
1269 * 01 = The forwarding map in FORWARD is OR'ed with the forwarding
1270 * map from the Address Lookup Table.
1271 * 10 = The forwarding map in FORWARD is AND'ed with the forwarding
1272 * map from the Address Lookup Table.
1273 * 11 = The forwarding map in FORWARD replaces the forwarding map
1274 * from the Address Lookup Table.
1275 * 0x0D - FORWARD[n:0]
1276 * Bits 7:0 - FORWARD[n:0] - Forwarding map. Bit 0 = port 1,
1277 * bit 1 = port 2, etc.
1278 * 1 = enable forwarding to this port
1279 * 0 = do not forward to this port
1281 void ksz9477_acl_action_rule_cfg(u8
*entry
, bool force_prio
, u8 prio_val
)
1286 prio_mode
= KSZ9477_ACL_PM_REPLACE
;
1288 prio_mode
= KSZ9477_ACL_PM_DISABLE
;
1290 val
= FIELD_PREP(KSZ9477_ACL_PM_M
, prio_mode
) |
1291 FIELD_PREP(KSZ9477_ACL_P_M
, prio_val
);
1292 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_A
, val
);
1294 /* no port or VLAN PCP remapping for now */
1295 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_B
, 0);
1296 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_D
, 0);
1300 * ksz9477_acl_processing_rule_set_action - Set the action for the processing
1302 * @entry: Pointer to the ACL entry
1303 * @action_idx: Index of the action to be applied
1305 * This function sets the action for the processing rule set by updating the
1306 * appropriate register in the entry. There can be only one action per
1309 * Access Control List (ACL) Processing Rule Registers:
1311 * 0x00 - First Rule Number (FRN)
1312 * Bits 3:0 - First Rule Number. Pointer to an Action rule entry.
1314 void ksz9477_acl_processing_rule_set_action(u8
*entry
, u8 action_idx
)
1316 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_0
, action_idx
);
1320 * ksz9477_acl_processing_rule_add_match - Add a matching rule to the rule set
1321 * @entry: Pointer to the ACL entry
1322 * @match_idx: Index of the matching rule to be added
1324 * This function adds a matching rule to the rule set by updating the
1325 * appropriate bits in the entry's rule set registers.
1327 * Access Control List (ACL) Processing Rule Registers:
1329 * 0x0E - RuleSet [15:8]
1330 * Bits 7:0 - RuleSet [15:8] Specifies a set of one or more Matching rule
1331 * entries. RuleSet has one bit for each of the 16 Matching rule entries.
1332 * If multiple Matching rules are selected, then all conditions will be
1333 * AND'ed to produce a final match result.
1334 * 0 = Matching rule not selected
1335 * 1 = Matching rule selected
1337 * 0x0F - RuleSet [7:0]
1338 * Bits 7:0 - RuleSet [7:0]
1340 static void ksz9477_acl_processing_rule_add_match(u8
*entry
, u8 match_idx
)
1342 u8 vale
= entry
[KSZ9477_ACL_PORT_ACCESS_E
];
1343 u8 valf
= entry
[KSZ9477_ACL_PORT_ACCESS_F
];
1346 valf
|= BIT(match_idx
);
1348 vale
|= BIT(match_idx
- 8);
1350 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_E
, vale
);
1351 ksz9477_acl_set_reg(entry
, KSZ9477_ACL_PORT_ACCESS_F
, valf
);
1355 * ksz9477_acl_get_init_entry - Get a new uninitialized entry for a specified
1356 * port on a ksz_device.
1357 * @dev: The ksz_device instance.
1358 * @port: The port number to get the uninitialized entry for.
1359 * @cookie: The cookie to associate with the entry.
1360 * @prio: The priority to associate with the entry.
1362 * This function retrieves the next available ACL entry for the specified port,
1363 * clears all access flags, and associates it with the current cookie.
1365 * Returns: A pointer to the new uninitialized ACL entry.
1367 static struct ksz9477_acl_entry
*
1368 ksz9477_acl_get_init_entry(struct ksz_device
*dev
, int port
,
1369 unsigned long cookie
, u32 prio
)
1371 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
1372 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
1373 struct ksz9477_acl_entry
*entry
;
1375 entry
= &acles
->entries
[acles
->entries_count
];
1376 entry
->cookie
= cookie
;
1379 /* clear all access flags */
1380 entry
->entry
[KSZ9477_ACL_PORT_ACCESS_10
] = 0;
1381 entry
->entry
[KSZ9477_ACL_PORT_ACCESS_11
] = 0;
1387 * ksz9477_acl_match_process_l2 - Configure Layer 2 ACL matching rules and
1389 * @dev: Pointer to the ksz_device.
1390 * @port: Port number.
1391 * @ethtype: Ethernet type.
1392 * @src_mac: Source MAC address.
1393 * @dst_mac: Destination MAC address.
1394 * @cookie: The cookie to associate with the entry.
1395 * @prio: The priority of the entry.
1397 * This function sets up matching and processing rules for Layer 2 ACLs.
1398 * It takes into account that only one MAC per entry is supported.
1400 void ksz9477_acl_match_process_l2(struct ksz_device
*dev
, int port
,
1401 u16 ethtype
, u8
*src_mac
, u8
*dst_mac
,
1402 unsigned long cookie
, u32 prio
)
1404 struct ksz9477_acl_priv
*acl
= dev
->ports
[port
].acl_priv
;
1405 struct ksz9477_acl_entries
*acles
= &acl
->acles
;
1406 struct ksz9477_acl_entry
*entry
;
1408 entry
= ksz9477_acl_get_init_entry(dev
, port
, cookie
, prio
);
1410 /* ACL supports only one MAC per entry */
1411 if (src_mac
&& dst_mac
) {
1412 ksz9477_acl_matching_rule_cfg_l2(entry
->entry
, ethtype
, src_mac
,
1415 /* Add both match entries to first processing rule */
1416 ksz9477_acl_processing_rule_add_match(entry
->entry
,
1417 acles
->entries_count
);
1418 acles
->entries_count
++;
1419 ksz9477_acl_processing_rule_add_match(entry
->entry
,
1420 acles
->entries_count
);
1422 entry
= ksz9477_acl_get_init_entry(dev
, port
, cookie
, prio
);
1423 ksz9477_acl_matching_rule_cfg_l2(entry
->entry
, 0, dst_mac
,
1425 acles
->entries_count
++;
1427 u8
*mac
= src_mac
? src_mac
: dst_mac
;
1428 bool is_src
= src_mac
? true : false;
1430 ksz9477_acl_matching_rule_cfg_l2(entry
->entry
, ethtype
, mac
,
1432 ksz9477_acl_processing_rule_add_match(entry
->entry
,
1433 acles
->entries_count
);
1434 acles
->entries_count
++;