drivers/net/dsa/microchip/ksz9477_acl.c

Source file repositories/reference/linux-study-clean/drivers/net/dsa/microchip/ksz9477_acl.c

File Facts

System
Linux kernel
Corpus path
drivers/net/dsa/microchip/ksz9477_acl.c
Extension
.c
Size
46962 bytes
Lines
1437
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ksz9477_acl_is_valid_matching_rule(entry)) {
			/* Looks like we are about to corrupt some complex rule.
			 * Do not print an error here, as this is a normal case
			 * when we are trying to find a free or starting entry.
			 */
			dev_dbg(dev->dev, "ACL: entry %d starting with a valid matching rule, but no bits set in RuleSet\n",
				index);
			return -ENOTEMPTY;
		}

		/* This entry does not contain a valid matching rule */
		return 0;
	}

	start_idx = find_first_bit((unsigned long *)&val, 16);
	end_idx = find_last_bit((unsigned long *)&val, 16);

	/* Calculate the contiguous count */
	contiguous_count = end_idx - start_idx + 1;

	/* Check if the number of bits set in val matches our calculated count */
	if (contiguous_count != hweight16(val)) {
		/* Probably we have a fragmented complex rule, which is not
		 * supported by this driver.
		 */
		dev_err(dev->dev, "ACL: number of bits set in RuleSet does not match calculated count\n");
		return -EINVAL;
	}

	/* loop over the contiguous entries and check for valid matching rules */
	for (i = start_idx; i <= end_idx; i++) {
		u8 *current_entry = &acles->entries[i].entry[0];

		if (!ksz9477_acl_is_valid_matching_rule(current_entry)) {
			/* we have something linked without a valid matching
			 * rule. ACL table?
			 */
			dev_err(dev->dev, "ACL: entry %d does not contain a valid matching rule\n",
				i);
			return -EINVAL;
		}

		if (i > start_idx) {
			vale = current_entry[KSZ9477_ACL_PORT_ACCESS_E];
			valf = current_entry[KSZ9477_ACL_PORT_ACCESS_F];
			/* Following entry should have empty linkage list */
			if (vale || valf) {
				dev_err(dev->dev, "ACL: entry %d has non-empty RuleSet linkage\n",
					i);
				return -EINVAL;
			}
		}
	}

	return contiguous_count;
}

/**
 * ksz9477_acl_update_linkage - Update the RuleSet linkage for an ACL entry
 *                              after a move operation.
 *
 * @dev: Pointer to the ksz_device.
 * @entry:   Pointer to the ACL entry array.
 * @old_idx: The original index of the ACL entry before moving.
 * @new_idx: The new index of the ACL entry after moving.
 *
 * This function updates the RuleSet linkage bits for an ACL entry when
 * it's moved from one position to another in the ACL table. The RuleSet
 * linkage is represented by two 8-bit registers, which are combined
 * into a 16-bit value for easier manipulation. The linkage bits are shifted
 * based on the difference between the old and new index. If any bits are lost
 * during the shift operation, an error is returned.
 *
 * Note: Fragmentation within a RuleSet is not supported. Hence, entries must
 * be moved as complete blocks, maintaining the integrity of the RuleSet.
 *
 * Returns: 0 on success, or -EINVAL if any RuleSet linkage bits are lost
 * during the move.
 */
static int ksz9477_acl_update_linkage(struct ksz_device *dev, u8 *entry,
				      u16 old_idx, u16 new_idx)
{
	unsigned int original_bit_count;
	unsigned long rule_linkage;
	u8 vale, valf, val0;
	int shift;

	val0 = entry[KSZ9477_ACL_PORT_ACCESS_0];
	vale = entry[KSZ9477_ACL_PORT_ACCESS_E];
	valf = entry[KSZ9477_ACL_PORT_ACCESS_F];

Annotation

Implementation Notes