1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> 3 4 /* Access Control List (ACL) structure: 5 * 6 * There are multiple groups of registers involved in ACL configuration: 7 * 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. 12 * 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. 17 * 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. 21 * 22 * ACL Structure: 23 * +----------------------+ 24 * +----------------------+ | (optional) | 25 * | Matching Rules | | Matching Rules | 26 * | (Layer 2, 3, 4) | | (Layer 2, 3, 4) | 27 * +----------------------+ +----------------------+ 28 * | | 29 * \___________________________/ 30 * v 31 * +----------------------+ 32 * | Processing Rules | 33 * | (action idx, | 34 * | matching rule set) | 35 * +----------------------+ 36 * | 37 * v 38 * +----------------------+ 39 * | Action Rules | 40 * | (Modify Priority, | 41 * | Forwarding Map, | 42 * | VLAN tag, etc) | 43 * +----------------------+ 44 */ 45 46 #include <linux/bitops.h> 47 48 #include "ksz9477.h" 49 #include "ksz9477_reg.h" 50 #include "ksz_common.h" 51 52 #define KSZ9477_PORT_ACL_0 0x600 53 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 73 }; 74 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 80 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 86 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 91 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 96 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 101 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) 108 109 #define KSZ9477_PORT_ACL_CTRL_0 0x0612 110 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) 115 116 /** 117 * ksz9477_dump_acl_index - Print the ACL entry at the specified index 118 * 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. 122 * 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 125 * are empty. 126 * 127 * Return: 1 if the entry is non-empty and printed, 0 otherwise. 128 */ 129 static int ksz9477_dump_acl_index(struct ksz_device *dev, 130 struct ksz9477_acl_entry *acle, int index) 131 { 132 bool empty = true; 133 char buf[64]; 134 u8 *entry; 135 int i; 136 137 entry = &acle[index].entry[0]; 138 for (i = 0; i <= KSZ9477_ACL_PORT_ACCESS_11; i++) { 139 if (entry[i]) 140 empty = false; 141 142 sprintf(buf + (i * 3), "%02x ", entry[i]); 143 } 144 145 /* no need to print empty entries */ 146 if (empty) 147 return 0; 148 149 dev_err(dev->dev, " Entry %02d, prio: %02d : %s", index, 150 acle[index].prio, buf); 151 152 return 1; 153 } 154 155 /** 156 * ksz9477_dump_acl - Print ACL entries 157 * 158 * @dev: Pointer to the device structure. 159 * @acle: Pointer to the ACL entry array. 160 */ 161 static void ksz9477_dump_acl(struct ksz_device *dev, 162 struct ksz9477_acl_entry *acle) 163 { 164 int count = 0; 165 int i; 166 167 for (i = 0; i < KSZ9477_ACL_MAX_ENTRIES; i++) 168 count += ksz9477_dump_acl_index(dev, acle, i); 169 170 if (count != KSZ9477_ACL_MAX_ENTRIES - 1) 171 dev_err(dev->dev, " Empty ACL entries were skipped\n"); 172 } 173 174 /** 175 * ksz9477_acl_is_valid_matching_rule - Check if an ACL entry contains a valid 176 * matching rule. 177 * 178 * @entry: Pointer to ACL entry buffer 179 * 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. 182 * 183 * Returns: True if it's a valid matching rule, false otherwise. 184 */ 185 static bool ksz9477_acl_is_valid_matching_rule(u8 *entry) 186 { 187 u8 val1, md, enb; 188 189 val1 = entry[KSZ9477_ACL_PORT_ACCESS_1]; 190 191 md = FIELD_GET(KSZ9477_ACL_MD_MASK, val1); 192 if (md == KSZ9477_ACL_MD_DISABLE) 193 return false; 194 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) 199 return false; 200 } 201 202 return true; 203 } 204 205 /** 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. 211 * 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. 217 * 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. 221 * 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. 225 * 226 * Returns: 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 230 * rule 231 * - -ENOTEMPTY if the entry is part of a complex rule but not the root 232 * entry 233 * - -EINVAL if the validation fails 234 */ 235 static int ksz9477_acl_get_cont_entr(struct ksz_device *dev, int port, 236 int index) 237 { 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; 241 unsigned long val; 242 u8 vale, valf; 243 u8 *entry; 244 int i; 245 246 entry = &acles->entries[index].entry[0]; 247 vale = entry[KSZ9477_ACL_PORT_ACCESS_E]; 248 valf = entry[KSZ9477_ACL_PORT_ACCESS_F]; 249 250 val = (vale << 8) | valf; 251 252 /* If no bits are set, return an appropriate value or error */ 253 if (!val) { 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. 258 */ 259 dev_dbg(dev->dev, "ACL: entry %d starting with a valid matching rule, but no bits set in RuleSet\n", 260 index); 261 return -ENOTEMPTY; 262 } 263 264 /* This entry does not contain a valid matching rule */ 265 return 0; 266 } 267 268 start_idx = find_first_bit((unsigned long *)&val, 16); 269 end_idx = find_last_bit((unsigned long *)&val, 16); 270 271 /* Calculate the contiguous count */ 272 contiguous_count = end_idx - start_idx + 1; 273 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. 278 */ 279 dev_err(dev->dev, "ACL: number of bits set in RuleSet does not match calculated count\n"); 280 return -EINVAL; 281 } 282 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]; 286 287 if (!ksz9477_acl_is_valid_matching_rule(current_entry)) { 288 /* we have something linked without a valid matching 289 * rule. ACL table? 290 */ 291 dev_err(dev->dev, "ACL: entry %d does not contain a valid matching rule\n", 292 i); 293 return -EINVAL; 294 } 295 296 if (i > start_idx) { 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 */ 300 if (vale || valf) { 301 dev_err(dev->dev, "ACL: entry %d has non-empty RuleSet linkage\n", 302 i); 303 return -EINVAL; 304 } 305 } 306 } 307 308 return contiguous_count; 309 } 310 311 /** 312 * ksz9477_acl_update_linkage - Update the RuleSet linkage for an ACL entry 313 * after a move operation. 314 * 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. 319 * 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. 326 * 327 * Note: Fragmentation within a RuleSet is not supported. Hence, entries must 328 * be moved as complete blocks, maintaining the integrity of the RuleSet. 329 * 330 * Returns: 0 on success, or -EINVAL if any RuleSet linkage bits are lost 331 * during the move. 332 */ 333 static int ksz9477_acl_update_linkage(struct ksz_device *dev, u8 *entry, 334 u16 old_idx, u16 new_idx) 335 { 336 unsigned int original_bit_count; 337 unsigned long rule_linkage; 338 u8 vale, valf, val0; 339 int shift; 340 341 val0 = entry[KSZ9477_ACL_PORT_ACCESS_0]; 342 vale = entry[KSZ9477_ACL_PORT_ACCESS_E]; 343 valf = entry[KSZ9477_ACL_PORT_ACCESS_F]; 344 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); 348 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. 351 */ 352 if (!rule_linkage) 353 return 0; 354 355 if (val0 != old_idx) { 356 dev_err(dev->dev, "ACL: entry %d has unexpected ActionRule linkage: %d\n", 357 old_idx, val0); 358 return -EINVAL; 359 } 360 361 val0 = new_idx; 362 363 /* Calculate the number of positions to shift */ 364 shift = new_idx - old_idx; 365 366 /* Shift the RuleSet */ 367 if (shift > 0) 368 rule_linkage <<= shift; 369 else 370 rule_linkage >>= -shift; 371 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"); 375 return -EINVAL; 376 } 377 378 entry[KSZ9477_ACL_PORT_ACCESS_0] = val0; 379 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; 383 384 return 0; 385 } 386 387 /** 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 394 * be moved. 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. 399 * 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. 407 * 408 * Return: 0 on success, otherwise returns a negative error code if any 409 * validation check fails. 410 */ 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) 414 { 415 int ret; 416 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"); 420 return -EINVAL; 421 } 422 423 /* Validate if the source entries are contiguous */ 424 ret = ksz9477_acl_get_cont_entr(dev, port, src_idx); 425 if (ret < 0) 426 return ret; 427 *src_count = ret; 428 429 if (!*src_count) { 430 dev_err(dev->dev, "ACL: source entry is empty\n"); 431 return -EINVAL; 432 } 433 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"); 436 return -EINVAL; 437 } 438 439 /* Validate if the destination entry is empty or not in the middle of 440 * a RuleSet. 441 */ 442 ret = ksz9477_acl_get_cont_entr(dev, port, dst_idx); 443 if (ret < 0) 444 return ret; 445 *dst_count = ret; 446 447 return 0; 448 } 449 450 /** 451 * ksz9477_move_entries_downwards - Move a range of ACL entries downwards in 452 * the list. 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 458 * relocation. 459 * 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. 464 * 465 * Return: 0 on successful relocation of entries, otherwise returns a negative 466 * error code. 467 */ 468 static int ksz9477_move_entries_downwards(struct ksz_device *dev, 469 struct ksz9477_acl_entries *acles, 470 u16 start_idx, 471 u16 num_entries_to_move, 472 u16 end_idx) 473 { 474 struct ksz9477_acl_entry *e; 475 int ret, i; 476 477 for (i = start_idx; i < end_idx; i++) { 478 e = &acles->entries[i]; 479 *e = acles->entries[i + num_entries_to_move]; 480 481 ret = ksz9477_acl_update_linkage(dev, &e->entry[0], 482 i + num_entries_to_move, i); 483 if (ret < 0) 484 return ret; 485 } 486 487 return 0; 488 } 489 490 /** 491 * ksz9477_move_entries_upwards - Move a range of ACL entries upwards in the 492 * list. 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 498 * after moving. 499 * 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. 503 * 504 * Return: 0 if the entries were successfully moved, otherwise a negative error 505 * code. 506 */ 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, 510 u16 target_idx) 511 { 512 struct ksz9477_acl_entry *e; 513 int ret, i, b; 514 515 for (i = start_idx; i > target_idx; i--) { 516 b = i + num_entries_to_move - 1; 517 518 e = &acles->entries[b]; 519 *e = acles->entries[i - 1]; 520 521 ret = ksz9477_acl_update_linkage(dev, &e->entry[0], i - 1, b); 522 if (ret < 0) 523 return ret; 524 } 525 526 return 0; 527 } 528 529 /** 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. 536 * 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 539 * the ACL table. 540 * 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. 543 * 544 * Return: 0 if the move operation is successful. Returns -EINVAL for validation 545 * errors or other error codes based on specific failure conditions. 546 */ 547 static int ksz9477_acl_move_entries(struct ksz_device *dev, int port, 548 u16 src_idx, u16 dst_idx) 549 { 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; 554 555 /* Nothing to do */ 556 if (src_idx == dst_idx) 557 return 0; 558 559 ret = ksz9477_validate_and_get_src_count(dev, port, src_idx, dst_idx, 560 &src_count, &dst_count); 561 if (ret) 562 return ret; 563 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. 567 */ 568 if (dst_idx > src_idx) 569 dst_idx = dst_idx + dst_count - src_count; 570 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); 576 if (ret < 0) 577 return ret; 578 } 579 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, 583 src_count, dst_idx); 584 } else { 585 ret = ksz9477_move_entries_upwards(dev, acles, src_idx, 586 src_count, dst_idx); 587 } 588 if (ret < 0) 589 return ret; 590 591 /* Copy buffer to destination block */ 592 for (int i = 0; i < src_count; i++) 593 acles->entries[dst_idx + i] = buffer[i]; 594 595 return 0; 596 } 597 598 /** 599 * ksz9477_get_next_block_start - Identify the starting index of the next ACL 600 * block. 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. 604 * 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. 609 * 610 * Returns: 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. 614 */ 615 static int ksz9477_get_next_block_start(struct ksz_device *dev, int port, 616 int start) 617 { 618 int block_size; 619 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) 623 return block_size; 624 625 if (block_size > 0) 626 return i; 627 628 i++; 629 } 630 return KSZ9477_ACL_MAX_ENTRIES; 631 } 632 633 /** 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. 639 * 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'. 645 * 646 * Returns: 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. 650 */ 651 static int ksz9477_swap_acl_blocks(struct ksz_device *dev, int port, int i, 652 int j) 653 { 654 int ret, current_block_size; 655 656 current_block_size = ksz9477_acl_get_cont_entr(dev, port, i); 657 if (current_block_size < 0) 658 return current_block_size; 659 660 if (!current_block_size) { 661 dev_err(dev->dev, "ACL: swapping empty entry %d\n", i); 662 return -EINVAL; 663 } 664 665 ret = ksz9477_acl_move_entries(dev, port, i, j); 666 if (ret) 667 return ret; 668 669 ret = ksz9477_acl_move_entries(dev, port, j - current_block_size, i); 670 if (ret) 671 return ret; 672 673 return 0; 674 } 675 676 /** 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. 681 * 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 687 * swapped. 688 * 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. 691 * 692 * Returns: 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. 696 */ 697 static int ksz9477_sort_acl_entr_no_back(struct ksz_device *dev, int port) 698 { 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; 702 int i, j, ret; 703 704 /* Bubble sort */ 705 for (i = 0; i < KSZ9477_ACL_MAX_ENTRIES;) { 706 curr = &acles->entries[i]; 707 708 j = ksz9477_get_next_block_start(dev, port, i + 1); 709 if (j < 0) 710 return j; 711 712 while (j < KSZ9477_ACL_MAX_ENTRIES) { 713 next = &acles->entries[j]; 714 715 if (curr->prio > next->prio) { 716 ret = ksz9477_swap_acl_blocks(dev, port, i, j); 717 if (ret) 718 return ret; 719 } 720 721 j = ksz9477_get_next_block_start(dev, port, j + 1); 722 if (j < 0) 723 return j; 724 } 725 726 i = ksz9477_get_next_block_start(dev, port, i + 1); 727 if (i < 0) 728 return i; 729 } 730 731 return 0; 732 } 733 734 /** 735 * ksz9477_sort_acl_entries - Sort the ACL entries for a given port. 736 * @dev: Pointer to the KSZ device. 737 * @port: Port number. 738 * 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. 744 * 745 * Return: 0 if the sorting succeeds, otherwise a negative error code. 746 */ 747 int ksz9477_sort_acl_entries(struct ksz_device *dev, int port) 748 { 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; 752 int ret; 753 754 /* create a backup of the ACL entries, if something goes wrong 755 * we can restore the ACL entries. 756 */ 757 memcpy(backup, acles->entries, sizeof(backup)); 758 759 ret = ksz9477_sort_acl_entr_no_back(dev, port); 760 if (ret) { 761 dev_err(dev->dev, "ACL: failed to sort entries for port %d\n", 762 port); 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)); 769 } 770 771 return ret; 772 } 773 774 /** 775 * ksz9477_acl_wait_ready - Waits for the ACL operation to complete on a given 776 * port. 777 * @dev: The ksz_device instance. 778 * @port: The port number to wait for. 779 * 780 * This function checks if the ACL write or read operation is completed by 781 * polling the specified register. 782 * 783 * Returns: 0 if the operation is successful, or a negative error code if an 784 * error occurs. 785 */ 786 static int ksz9477_acl_wait_ready(struct ksz_device *dev, int port) 787 { 788 unsigned int wr_mask = KSZ9477_ACL_WRITE_DONE | KSZ9477_ACL_READ_DONE; 789 unsigned int val, reg; 790 int ret; 791 792 reg = dev->dev_ops->get_port_addr(port, KSZ9477_PORT_ACL_CTRL_0); 793 794 ret = regmap_read_poll_timeout(dev->regmap[0], reg, val, 795 (val & wr_mask) == wr_mask, 1000, 10000); 796 if (ret) 797 dev_err(dev->dev, "Failed to read/write ACL table\n"); 798 799 return ret; 800 } 801 802 /** 803 * ksz9477_acl_entry_write - Writes an ACL entry to a given port at the 804 * specified index. 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. 809 * 810 * This function writes the provided ACL entry to the specified port at the 811 * given index. 812 * 813 * Returns: 0 if the operation is successful, or a negative error code if an 814 * error occurs. 815 */ 816 static int ksz9477_acl_entry_write(struct ksz_device *dev, int port, u8 *entry, 817 int idx) 818 { 819 int ret, i; 820 u8 val; 821 822 for (i = 0; i < KSZ9477_ACL_ENTRY_SIZE; i++) { 823 ret = ksz_pwrite8(dev, port, KSZ9477_PORT_ACL_0 + i, entry[i]); 824 if (ret) { 825 dev_err(dev->dev, "Failed to write ACL entry %d\n", i); 826 return ret; 827 } 828 } 829 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); 833 if (ret) 834 return ret; 835 836 /* wait until everything is written */ 837 return ksz9477_acl_wait_ready(dev, port); 838 } 839 840 /** 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. 844 * 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. 848 * 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 857 * 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. 861 * 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 865 * 00 = Reserved 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 875 * ACL actions apply. 876 * 877 * We are using Pass Mode int this function. 878 * 879 * Returns: 0 if the operation is successful, or a negative error code if an 880 * error occurs. 881 */ 882 static int ksz9477_acl_port_enable(struct ksz_device *dev, int port) 883 { 884 int ret; 885 886 ret = ksz_prmw8(dev, port, P_PRIO_CTRL, 0, PORT_ACL_PRIO_ENABLE | 887 PORT_OR_PRIO); 888 if (ret) 889 return ret; 890 891 return ksz_pwrite8(dev, port, REG_PORT_MRI_AUTHEN_CTRL, 892 PORT_ACL_ENABLE | 893 FIELD_PREP(PORT_AUTHEN_MODE, PORT_AUTHEN_PASS)); 894 } 895 896 /** 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. 900 * 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. 904 * 905 * Returns: 0 if the operation is successful, or a negative error code if an 906 * error occurs. 907 */ 908 static int ksz9477_acl_port_disable(struct ksz_device *dev, int port) 909 { 910 int ret; 911 912 ret = ksz_prmw8(dev, port, P_PRIO_CTRL, PORT_ACL_PRIO_ENABLE, 0); 913 if (ret) 914 return ret; 915 916 return ksz_pwrite8(dev, port, REG_PORT_MRI_AUTHEN_CTRL, 0); 917 } 918 919 /** 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. 923 * 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 926 * entries. 927 * 928 * Returns: 0 if the operation is successful, or a negative error code if an 929 * error occurs. 930 */ 931 int ksz9477_acl_write_list(struct ksz_device *dev, int port) 932 { 933 struct ksz9477_acl_priv *acl = dev->ports[port].acl_priv; 934 struct ksz9477_acl_entries *acles = &acl->acles; 935 int ret, i; 936 937 /* ACL should be enabled before writing entries */ 938 ret = ksz9477_acl_port_enable(dev, port); 939 if (ret) 940 return ret; 941 942 /* write all entries */ 943 for (i = 0; i < ARRAY_SIZE(acles->entries); i++) { 944 u8 *entry = acles->entries[i].entry; 945 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. 950 */ 951 if (i >= acles->entries_count && 952 entry[KSZ9477_ACL_PORT_ACCESS_10] == 0 && 953 entry[KSZ9477_ACL_PORT_ACCESS_11] == 0) 954 continue; 955 956 ret = ksz9477_acl_entry_write(dev, port, entry, i); 957 if (ret) 958 return ret; 959 960 /* now removed entry is clean on HW side, so it can 961 * in the cache too 962 */ 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; 968 } 969 } 970 971 if (!acles->entries_count) 972 return ksz9477_acl_port_disable(dev, port); 973 974 return 0; 975 } 976 977 /** 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. 984 * 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 987 * the gap. 988 */ 989 void ksz9477_acl_remove_entries(struct ksz_device *dev, int port, 990 struct ksz9477_acl_entries *acles, 991 unsigned long cookie) 992 { 993 int entries_count = acles->entries_count; 994 int ret, i, src_count; 995 int src_idx = -1; 996 997 if (!entries_count) 998 return; 999 1000 /* Search for the first position with the cookie */ 1001 for (i = 0; i < entries_count; i++) { 1002 if (acles->entries[i].cookie == cookie) { 1003 src_idx = i; 1004 break; 1005 } 1006 } 1007 1008 /* No entries with the matching cookie found */ 1009 if (src_idx == -1) 1010 return; 1011 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); 1014 if (src_count <= 0) 1015 return; 1016 1017 /* Move all entries down to overwrite removed entry with the cookie */ 1018 ret = ksz9477_move_entries_downwards(dev, acles, src_idx, 1019 src_count, 1020 entries_count - src_count); 1021 if (ret) { 1022 dev_err(dev->dev, "Failed to move ACL entries down\n"); 1023 return; 1024 } 1025 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 1028 * come out. 1029 */ 1030 for (i = entries_count - src_count; i < entries_count; i++) { 1031 struct ksz9477_acl_entry *entry = &acles->entries[i]; 1032 1033 memset(entry, 0, sizeof(*entry)); 1034 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; 1038 } 1039 1040 /* Adjust the total entries count */ 1041 acles->entries_count -= src_count; 1042 } 1043 1044 /** 1045 * ksz9477_port_acl_init - Initialize the ACL for a specified port on a ksz 1046 * device. 1047 * @dev: The ksz_device instance. 1048 * @port: The port number to initialize the ACL for. 1049 * 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. 1054 * 1055 * Returns: 0 on success, or an error code on failure. 1056 */ 1057 int ksz9477_port_acl_init(struct ksz_device *dev, int port) 1058 { 1059 struct ksz9477_acl_entries *acles; 1060 struct ksz9477_acl_priv *acl; 1061 int ret, i; 1062 1063 acl = kzalloc(sizeof(*acl), GFP_KERNEL); 1064 if (!acl) 1065 return -ENOMEM; 1066 1067 dev->ports[port].acl_priv = acl; 1068 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; 1073 1074 /* Set all access bits to be able to write zeroed 1075 * entry 1076 */ 1077 entry[KSZ9477_ACL_PORT_ACCESS_10] = 0xff; 1078 entry[KSZ9477_ACL_PORT_ACCESS_11] = 0xff; 1079 } 1080 1081 ret = ksz9477_acl_write_list(dev, port); 1082 if (ret) 1083 goto free_acl; 1084 1085 return 0; 1086 1087 free_acl: 1088 kfree(dev->ports[port].acl_priv); 1089 dev->ports[port].acl_priv = NULL; 1090 1091 return ret; 1092 } 1093 1094 /** 1095 * ksz9477_port_acl_free - Free the ACL resources for a specified port on a ksz 1096 * device. 1097 * @dev: The ksz_device instance. 1098 * @port: The port number to initialize the ACL for. 1099 * 1100 * This disables the ACL for the specified port and frees the associated memory, 1101 */ 1102 void ksz9477_port_acl_free(struct ksz_device *dev, int port) 1103 { 1104 if (!dev->ports[port].acl_priv) 1105 return; 1106 1107 ksz9477_acl_port_disable(dev, port); 1108 1109 kfree(dev->ports[port].acl_priv); 1110 dev->ports[port].acl_priv = NULL; 1111 } 1112 1113 /** 1114 * ksz9477_acl_set_reg - Set entry[16] and entry[17] depending on the updated 1115 * entry[] 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 1119 * 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 1122 * enable rules. 1123 * 1124 * 0x10 - Byte Enable [15:8] 1125 * 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 1133 * 1134 * 0x11 - Byte Enable [7:0] 1135 * 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 1143 */ 1144 static void ksz9477_acl_set_reg(u8 *entry, enum ksz9477_acl_port_access reg, 1145 u8 value) 1146 { 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); 1155 } else { 1156 WARN_ON(1); 1157 return; 1158 } 1159 1160 entry[reg] = value; 1161 } 1162 1163 /** 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 1171 * 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. 1176 * 1177 * Register Descriptions for MD = 01 and ENB != 00 (Layer 2 MAC header 1178 * filtering) 1179 * 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 1193 * 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] 1201 * 1202 * 0x08-0x09 - EtherType 1203 * 0x08 - EtherType [15:8] 1204 * 0x09 - EtherType [7:0] 1205 */ 1206 static void ksz9477_acl_matching_rule_cfg_l2(u8 *entry, u16 ethertype, 1207 u8 *eth_addr, bool is_src) 1208 { 1209 u8 enb = 0; 1210 u8 val; 1211 1212 if (ethertype) 1213 enb |= KSZ9477_ACL_ENB_L2_TYPE; 1214 if (eth_addr) 1215 enb |= KSZ9477_ACL_ENB_L2_MAC; 1216 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); 1221 1222 if (eth_addr) { 1223 int i; 1224 1225 for (i = 0; i < ETH_ALEN; i++) { 1226 ksz9477_acl_set_reg(entry, 1227 KSZ9477_ACL_PORT_ACCESS_2 + i, 1228 eth_addr[i]); 1229 } 1230 } 1231 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); 1234 } 1235 1236 /** 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 1241 * 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 1245 * remapping. 1246 * 1247 * ACL Action Rule Parameters for Non-Count Modes (MD ≠ 01 or ENB ≠ 00) 1248 * 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 1254 * result. 1255 * 10 = Change packet priority to P[2:0] if it is smaller than the 1256 * QoS result. 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]. 1264 * 1265 * 0x0B - RP[0], MM 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 1280 */ 1281 void ksz9477_acl_action_rule_cfg(u8 *entry, bool force_prio, u8 prio_val) 1282 { 1283 u8 prio_mode, val; 1284 1285 if (force_prio) 1286 prio_mode = KSZ9477_ACL_PM_REPLACE; 1287 else 1288 prio_mode = KSZ9477_ACL_PM_DISABLE; 1289 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); 1293 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); 1297 } 1298 1299 /** 1300 * ksz9477_acl_processing_rule_set_action - Set the action for the processing 1301 * rule set. 1302 * @entry: Pointer to the ACL entry 1303 * @action_idx: Index of the action to be applied 1304 * 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 1307 * processing rule. 1308 * 1309 * Access Control List (ACL) Processing Rule Registers: 1310 * 1311 * 0x00 - First Rule Number (FRN) 1312 * Bits 3:0 - First Rule Number. Pointer to an Action rule entry. 1313 */ 1314 void ksz9477_acl_processing_rule_set_action(u8 *entry, u8 action_idx) 1315 { 1316 ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_0, action_idx); 1317 } 1318 1319 /** 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 1323 * 1324 * This function adds a matching rule to the rule set by updating the 1325 * appropriate bits in the entry's rule set registers. 1326 * 1327 * Access Control List (ACL) Processing Rule Registers: 1328 * 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 1336 * 1337 * 0x0F - RuleSet [7:0] 1338 * Bits 7:0 - RuleSet [7:0] 1339 */ 1340 static void ksz9477_acl_processing_rule_add_match(u8 *entry, u8 match_idx) 1341 { 1342 u8 vale = entry[KSZ9477_ACL_PORT_ACCESS_E]; 1343 u8 valf = entry[KSZ9477_ACL_PORT_ACCESS_F]; 1344 1345 if (match_idx < 8) 1346 valf |= BIT(match_idx); 1347 else 1348 vale |= BIT(match_idx - 8); 1349 1350 ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_E, vale); 1351 ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_F, valf); 1352 } 1353 1354 /** 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. 1361 * 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. 1364 * 1365 * Returns: A pointer to the new uninitialized ACL entry. 1366 */ 1367 static struct ksz9477_acl_entry * 1368 ksz9477_acl_get_init_entry(struct ksz_device *dev, int port, 1369 unsigned long cookie, u32 prio) 1370 { 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; 1374 1375 entry = &acles->entries[acles->entries_count]; 1376 entry->cookie = cookie; 1377 entry->prio = prio; 1378 1379 /* clear all access flags */ 1380 entry->entry[KSZ9477_ACL_PORT_ACCESS_10] = 0; 1381 entry->entry[KSZ9477_ACL_PORT_ACCESS_11] = 0; 1382 1383 return entry; 1384 } 1385 1386 /** 1387 * ksz9477_acl_match_process_l2 - Configure Layer 2 ACL matching rules and 1388 * processing rules. 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. 1396 * 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. 1399 */ 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) 1403 { 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; 1407 1408 entry = ksz9477_acl_get_init_entry(dev, port, cookie, prio); 1409 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, 1413 true); 1414 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); 1421 1422 entry = ksz9477_acl_get_init_entry(dev, port, cookie, prio); 1423 ksz9477_acl_matching_rule_cfg_l2(entry->entry, 0, dst_mac, 1424 false); 1425 acles->entries_count++; 1426 } else { 1427 u8 *mac = src_mac ? src_mac : dst_mac; 1428 bool is_src = src_mac ? true : false; 1429 1430 ksz9477_acl_matching_rule_cfg_l2(entry->entry, ethtype, mac, 1431 is_src); 1432 ksz9477_acl_processing_rule_add_match(entry->entry, 1433 acles->entries_count); 1434 acles->entries_count++; 1435 } 1436 } 1437