/* only IPv4 src or dst can be used with mask */ #define KSZ9477_ACL_ENB_L3_IPV4_ADDR_MASK 1 /* only IPv4 src and dst can be used without mask */ #define KSZ9477_ACL_ENB_L3_IPV4_ADDR_SRC_DST 2
md = FIELD_GET(KSZ9477_ACL_MD_MASK, val1); if (md == KSZ9477_ACL_MD_DISABLE) returnfalse;
if (md == KSZ9477_ACL_MD_L2_MAC) { /* L2 counter is not support, so it is not valid rule for now */
enb = FIELD_GET(KSZ9477_ACL_ENB_MASK, val1); if (enb == KSZ9477_ACL_ENB_L2_COUNTER) returnfalse;
}
/* If no bits are set, return an appropriate value or error */ if (!val) { if (ksz9477_acl_is_valid_matching_rule(entry)) { /* Looks like we are about to corrupt some complex rule. *Donotprintanerrorhere,asthisisanormalcase *whenwearetryingtofindafreeorstartingentry.
*/
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 */ return0;
}
/* 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 *supportedbythisdriver.
*/
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.ACLtable?
*/
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;
}
}
}
/* Combine the two u8 values into one u16 for easier manipulation */
rule_linkage = (vale << 8) | valf;
original_bit_count = hweight16(rule_linkage);
/* Even if HW is able to handle fragmented RuleSet, we don't support it. *RuleSetisfilledonlyforthefirstentryoftheset.
*/ if (!rule_linkage) return0;
if (val0 != old_idx) {
dev_err(dev->dev, "ACL: entry %d has unexpected ActionRule linkage: %d\n",
old_idx, val0); return -EINVAL;
}
val0 = new_idx;
/* Calculate the number of positions to shift */
shift = new_idx - old_idx;
/* Shift the RuleSet */ if (shift > 0)
rule_linkage <<= shift; else
rule_linkage >>= -shift;
/* Check that no bits were lost in the process */ if (original_bit_count != hweight16(rule_linkage)) {
dev_err(dev->dev, "ACL RuleSet linkage bits lost during move\n"); return -EINVAL;
}
entry[KSZ9477_ACL_PORT_ACCESS_0] = val0;
/* Update the RuleSet bitfields in the entry */
entry[KSZ9477_ACL_PORT_ACCESS_E] = (rule_linkage >> 8) & 0xFF;
entry[KSZ9477_ACL_PORT_ACCESS_F] = rule_linkage & 0xFF;
return0;
}
/** *ksz9477_validate_and_get_src_count-Validatesourceanddestinationindices *anddeterminethesourceentrycount. *@dev:PointertotheKSZdevicestructure. *@port:PortnumberontheKSZdevicewheretheACLentriesreside. *@src_idx:IndexofthestartingACLentrythatneedstobevalidated. *@dst_idx:Indexofthedestinationwherethesourceentriesareintendedto *bemoved. *@src_count:Pointertothevariablethatwillholdthenumberofcontiguous *sourceentriesifthevalidationpasses. *@dst_count:Pointertothevariablethatwillholdthenumberofcontiguous *destinationentriesifthevalidationpasses. * *Thisfunctionperformsvalidationonthesourceanddestinationindices *providedforACLentries.Itchecksiftheindicesarewithinthevalid *range,andifthesourceentriesarecontiguous.Additionally,thefunction *ensuresthatthere'sadequatespaceatthedestinationforthesourceentries *andthatthedestinationindexisn'tinthemiddleofaRuleSet.Ifall *validationspass,thefunctionreturnsthenumberofcontiguoussourceand *destinationentries. * *Return:0onsuccess,otherwisereturnsanegativeerrorcodeifany *validationcheckfails.
*/ staticint ksz9477_validate_and_get_src_count(struct ksz_device *dev, int port, int src_idx, int dst_idx, int *src_count, int *dst_count)
{ int ret;
/* Validate if the source entries are contiguous */
ret = ksz9477_acl_get_cont_entr(dev, port, src_idx); if (ret < 0) return ret;
*src_count = ret;
if (!*src_count) {
dev_err(dev->dev, "ACL: source entry is empty\n"); return -EINVAL;
}
if (dst_idx + *src_count >= KSZ9477_ACL_MAX_ENTRIES) {
dev_err(dev->dev, "ACL: Not enough space at the destination. Move operation will fail.\n"); return -EINVAL;
}
/* Validate if the destination entry is empty or not in the middle of *aRuleSet.
*/
ret = ksz9477_acl_get_cont_entr(dev, port, dst_idx); if (ret < 0) return ret;
*dst_count = ret;
/* Nothing to do */ if (src_idx == dst_idx) return0;
ret = ksz9477_validate_and_get_src_count(dev, port, src_idx, dst_idx,
&src_count, &dst_count); if (ret) return ret;
/* In case dst_index is greater than src_index, we need to adjust the *destinationindextoaccountfortheentriesthatwillbemoved *downwardsandthesizeoftheentrylocatedatdst_idx.
*/ if (dst_idx > src_idx)
dst_idx = dst_idx + dst_count - src_count;
/* Copy source block to buffer and update its linkage */ for (int i = 0; i < src_count; i++) {
buffer[i] = acles->entries[src_idx + i];
ret = ksz9477_acl_update_linkage(dev, &buffer[i].entry[0],
src_idx + i, dst_idx + i); if (ret < 0) return ret;
}
/* Adjust other entries and their linkage based on destination */ if (dst_idx > src_idx) {
ret = ksz9477_move_entries_downwards(dev, acles, src_idx,
src_count, dst_idx);
} else {
ret = ksz9477_move_entries_upwards(dev, acles, src_idx,
src_count, dst_idx);
} if (ret < 0) return ret;
/* Copy buffer to destination block */ for (int i = 0; i < src_count; i++)
acles->entries[dst_idx + i] = buffer[i];
return0;
}
/** *ksz9477_get_next_block_start-IdentifythestartingindexofthenextACL *block. *@dev:Pointertothedevicestructure. *@port:TheportnumberonwhichtheACLentriesarebeingchecked. *@start:Thestartingindexfromwhichthesearchbegins. * *ThisfunctionlooksforthenextvalidACLblockstartingfromtheprovided *'start'indexandreturnsthebeginningindexofthatblock.Iftheblockis *invalidorifitreachestheendoftheACLentrieswithoutfindinganother *block,itreturnsthemaximumACLentriescount. * *Returns: *-ThestartingindexofthenextvalidACLblock. *-KSZ9477_ACL_MAX_ENTRIESifnoothervalidblocksarefoundafter'start'. *-Anegativeerrorcodeifanerroroccurswhilechecking.
*/ staticint ksz9477_get_next_block_start(struct ksz_device *dev, int port, int start)
{ int block_size;
for (int i = start; i < KSZ9477_ACL_MAX_ENTRIES;) {
block_size = ksz9477_acl_get_cont_entr(dev, port, i); if (block_size < 0 && block_size != -ENOTEMPTY) return block_size;
if (block_size > 0) return i;
i++;
} return KSZ9477_ACL_MAX_ENTRIES;
}
/** *ksz9477_swap_acl_blocks-SwaptwoACLblocks *@dev:Pointertothedevicestructure. *@port:TheportnumberonwhichtheACLblocksaretobeswapped. *@i:ThestartingindexofthefirstACLblock. *@j:ThestartingindexofthesecondACLblock. * *ThisfunctionisusedtoswaptwoACLblockspresentatgivenindices.The *mainpurposeistoaidinthesortingandreorderingofACLblocksbasedon *certaincriteria,e.g.,priority.Itchecksthevalidityoftheblockat *index'i',ensuringit'snotanemptyblock,andthenproceedstoswapit *withtheblockatindex'j'. * *Returns: *-0onsuccessfulswappingofblocks. *--EINVALiftheblockatindex'i'isempty. *-Anegativeerrorcodeifanyothererroroccursduringtheswap.
*/ staticint ksz9477_swap_acl_blocks(struct ksz_device *dev, int port, int i, int j)
{ int ret, current_block_size;
/* create a backup of the ACL entries, if something goes wrong *wecanrestoretheACLentries.
*/
memcpy(backup, acles->entries, sizeof(backup));
ret = ksz9477_sort_acl_entr_no_back(dev, port); if (ret) {
dev_err(dev->dev, "ACL: failed to sort entries for port %d\n",
port);
dev_err(dev->dev, "ACL dump before sorting:\n");
ksz9477_dump_acl(dev, backup);
dev_err(dev->dev, "ACL dump after sorting:\n");
ksz9477_dump_acl(dev, acles->entries); /* Restore the original entries */
memcpy(acles->entries, backup, sizeof(backup));
}
ret = regmap_read_poll_timeout(dev->regmap[0], reg, val,
(val & wr_mask) == wr_mask, 1000, 10000); if (ret)
dev_err(dev->dev, "Failed to read/write ACL table\n");
return ret;
}
/** *ksz9477_acl_entry_write-WritesanACLentrytoagivenportatthe *specifiedindex. *@dev:Theksz_deviceinstance. *@port:TheportnumbertowritetheACLentryto. *@entry:ApointertotheACLentrydata. *@idx:TheindexatwhichtowritetheACLentry. * *ThisfunctionwritestheprovidedACLentrytothespecifiedportatthe *givenindex. * *Returns:0iftheoperationissuccessful,oranegativeerrorcodeifan *erroroccurs.
*/ staticint ksz9477_acl_entry_write(struct ksz_device *dev, int port, u8 *entry, int idx)
{ int ret, i;
u8 val;
for (i = 0; i < KSZ9477_ACL_ENTRY_SIZE; i++) {
ret = ksz_pwrite8(dev, port, KSZ9477_PORT_ACL_0 + i, entry[i]); if (ret) {
dev_err(dev->dev, "Failed to write ACL entry %d\n", i); return ret;
}
}
/* write everything down */
val = FIELD_PREP(KSZ9477_ACL_INDEX_M, idx) | KSZ9477_ACL_WRITE;
ret = ksz_pwrite8(dev, port, KSZ9477_PORT_ACL_CTRL_0, val); if (ret) return ret;
/* wait until everything is written */ return ksz9477_acl_wait_ready(dev, port);
}
/* ACL should be enabled before writing entries */
ret = ksz9477_acl_port_enable(dev, port); if (ret) return ret;
/* write all entries */ for (i = 0; i < ARRAY_SIZE(acles->entries); i++) {
u8 *entry = acles->entries[i].entry;
/* Check if entry was removed and should be zeroed. *Iflastfieldsoftheentryarenotzero,itmeans *itisremovedlocallybutcurrentlynotsyncedwiththeHW. *So,wewillwriteitdowntotheHWtoremoveit.
*/ if (i >= acles->entries_count &&
entry[KSZ9477_ACL_PORT_ACCESS_10] == 0 &&
entry[KSZ9477_ACL_PORT_ACCESS_11] == 0) continue;
ret = ksz9477_acl_entry_write(dev, port, entry, i); if (ret) return ret;
/* now removed entry is clean on HW side, so it can *inthecachetoo
*/ if (i >= acles->entries_count &&
entry[KSZ9477_ACL_PORT_ACCESS_10] != 0 &&
entry[KSZ9477_ACL_PORT_ACCESS_11] != 0) {
entry[KSZ9477_ACL_PORT_ACCESS_10] = 0;
entry[KSZ9477_ACL_PORT_ACCESS_11] = 0;
}
}
if (!acles->entries_count) return ksz9477_acl_port_disable(dev, port);
return0;
}
/** *ksz9477_acl_remove_entries-RemoveACLentrieswithagivencookiefroma *specifiedksz9477_acl_entriesstructure. *@dev:Theksz_deviceinstance. *@port:TheportnumberonwhichtoremoveACLentries. *@acles:Theksz9477_acl_entriesinstance. *@cookie:Thecookievaluetomatchforentryremoval. * *Thisfunctioniteratesthroughtheentriesarray,removinganyentrieswith *amatchingcookievalue.Theremainingentriesarethenshifteddowntofill *thegap.
*/ void ksz9477_acl_remove_entries(struct ksz_device *dev, int port, struct ksz9477_acl_entries *acles, unsignedlong cookie)
{ int entries_count = acles->entries_count; int ret, i, src_count; int src_idx = -1;
if (!entries_count) return;
/* Search for the first position with the cookie */ for (i = 0; i < entries_count; i++) { if (acles->entries[i].cookie == cookie) {
src_idx = i; break;
}
}
/* No entries with the matching cookie found */ if (src_idx == -1) return;
/* Get the size of the cookie entry. We may have complex entries. */
src_count = ksz9477_acl_get_cont_entr(dev, port, src_idx); if (src_count <= 0) return;
/* Move all entries down to overwrite removed entry with the cookie */
ret = ksz9477_move_entries_downwards(dev, acles, src_idx,
src_count,
entries_count - src_count); if (ret) {
dev_err(dev->dev, "Failed to move ACL entries down\n"); return;
}
/* Overwrite new empty places at the end of the list with zeros to make *surenotunexpectedthingswillhappenornounexploredquirkswill *comeout.
*/ for (i = entries_count - src_count; i < entries_count; i++) { struct ksz9477_acl_entry *entry = &acles->entries[i];
memset(entry, 0, sizeof(*entry));
/* Set all access bits to be able to write zeroed entry to HW */
entry->entry[KSZ9477_ACL_PORT_ACCESS_10] = 0xff;
entry->entry[KSZ9477_ACL_PORT_ACCESS_11] = 0xff;
}
/* Adjust the total entries count */
acles->entries_count -= src_count;
}
/** *ksz9477_port_acl_init-InitializetheACLforaspecifiedportonaksz *device. *@dev:Theksz_deviceinstance. *@port:TheportnumbertoinitializetheACLfor. * *Thisfunctionallocatesmemoryforanaclstructure,associatesitwiththe *specifiedport,andinitializestheACLentriestoadefaultstate.The *entriesarethenwrittenusingtheksz9477_acl_write_listfunction,ensuring *theACLhasapredictableinitialhardwarestate. * *Returns:0onsuccess,oranerrorcodeonfailure.
*/ int ksz9477_port_acl_init(struct ksz_device *dev, int port)
{ struct ksz9477_acl_entries *acles; struct ksz9477_acl_priv *acl; int ret, i;
acl = kzalloc(sizeof(*acl), GFP_KERNEL); if (!acl) return -ENOMEM;
dev->ports[port].acl_priv = acl;
acles = &acl->acles; /* write all entries */ for (i = 0; i < ARRAY_SIZE(acles->entries); i++) {
u8 *entry = acles->entries[i].entry;
/* Set all access bits to be able to write zeroed *entry
*/
entry[KSZ9477_ACL_PORT_ACCESS_10] = 0xff;
entry[KSZ9477_ACL_PORT_ACCESS_11] = 0xff;
}
ret = ksz9477_acl_write_list(dev, port); if (ret) goto free_acl;
if (force_prio)
prio_mode = KSZ9477_ACL_PM_REPLACE; else
prio_mode = KSZ9477_ACL_PM_DISABLE;
val = FIELD_PREP(KSZ9477_ACL_PM_M, prio_mode) |
FIELD_PREP(KSZ9477_ACL_P_M, prio_val);
ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_A, val);
/* no port or VLAN PCP remapping for now */
ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_B, 0);
ksz9477_acl_set_reg(entry, KSZ9477_ACL_PORT_ACCESS_D, 0);
}
/* ACL supports only one MAC per entry */ if (src_mac && dst_mac) {
ksz9477_acl_matching_rule_cfg_l2(entry->entry, ethtype, src_mac, true);
/* Add both match entries to first processing rule */
ksz9477_acl_processing_rule_add_match(entry->entry,
acles->entries_count);
acles->entries_count++;
ksz9477_acl_processing_rule_add_match(entry->entry,
acles->entries_count);
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.37Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.