Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
   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
  54enum 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 */
 129static 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 */
 161static 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 */
 185static 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 */
 235static 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 */
 333static 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 */
 411static 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 */
 468static 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 */
 507static 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 */
 547static 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 */
 615static 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 */
 651static 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 */
 697static 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 */
 747int 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 */
 786static 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 */
 816static 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 */
 882static 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 */
 908static 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 */
 931int 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 */
 989void 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 */
1057int 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
1087free_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 */
1102void 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 */
1144static 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 */
1206static 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 */
1281void 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 */
1314void 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 */
1340static 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 */
1367static struct ksz9477_acl_entry *
1368ksz9477_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 */
1400void 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}