diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c index 2fdb0fb963f..9d8e0dd9eb6 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c @@ -201,28 +201,6 @@ static int rtldsa_ports_probe(struct rtl838x_switch_priv *priv) return 0; } -static int rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv) -{ - int t = sw_r32(priv->r->l2_ctrl_1); - - /* RTL838x uses a high-resolution 23-bit AGE_UNIT where one unit is - * 204.8 ms. RTL839x and RTL93xx use a 21-bit AGE_UNIT where one unit - * is 600 ms. An AGE_UNIT value of 0 disables dynamic address aging. - */ - if (priv->r->high_res_l2_age) { - t &= GENMASK(22, 0); - t = t * 128 / 625; - } else { - t &= GENMASK(20, 0); - t = t * 3 / 5; - } - - pr_debug("L2 AGING time: %d sec\n", t); - pr_debug("Dynamic aging for ports: %x\n", sw_r32(priv->r->l2_port_aging_out)); - - return t; -} - // Currently Unused // /* Allocate a 64 bit octet counter located in the LOG HW table */ // static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv) @@ -519,7 +497,7 @@ static int rtl83xx_sw_probe(struct platform_device *pdev) if (soc_info.family != RTL9310_FAMILY_ID) sw_w32(0x1, priv->r->imr_glb); - rtl83xx_get_l2aging(priv); + otto_l2_get_ageing_time(priv); if (priv->r->qos_init) priv->r->qos_init(priv); diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c index 9aabe10d476..4f12c05a4ac 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c @@ -797,87 +797,6 @@ static void rtldsa_setup_l2_mc_entry(struct rtl838x_l2_entry *e, int vid, u64 ma u64_to_ether_addr(mac, e->mac); } -static int rtldsa_l2_hash_index(u32 key, int slot) -{ - return slot > 3 ? ((key >> 14) & 0xffff) | (slot & 3) : ((key << 2) | slot) & 0xffff; -} - -/* Uses the seed to identify a hash bucket in the L2 using the derived hash key and then loops - * over the entries in the bucket until either a matching entry is found or an empty slot - * Returns the filled in rtl838x_l2_entry and the index in the bucket when an entry was found - * when an empty slot was found and must exist is false, the index of the slot is returned - * when no slots are available returns -1 - */ -int rtldsa_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed, - bool must_exist, struct rtl838x_l2_entry *e) -{ - u32 key = priv->r->l2_hash_key(priv, seed); - int free_slot = -1; - u64 entry; - - pr_debug("%s: using key %x, for seed %016llx\n", __func__, key, seed); - /* Loop over all entries in the hash-bucket and over the second block on 93xx SoCs */ - for (int i = 0; i < priv->r->l2_bucket_size; i++) { - entry = priv->r->read_l2_entry_using_hash(key, i, e); - pr_debug("valid %d, mac %016llx\n", e->valid, ether_addr_to_u64(&e->mac[0])); - - /* Remember the first free slot, but keep looking: the address - * may be sitting further down the bucket. - */ - if (!e->valid) { - if (free_slot < 0) - free_slot = i; - continue; - } - - if ((entry & 0x0fffffffffffffffULL) == seed) - return rtldsa_l2_hash_index(key, i); - } - - if (must_exist || free_slot < 0) - return -1; - - /* The loop leaves the last entry it read here, valid bit included. - * Reading the free slot back does not undo that on RTL930x and - * RTL931x, whose readers return as soon as the valid bit is clear. - */ - memset(e, 0, sizeof(*e)); - - return rtldsa_l2_hash_index(key, free_slot); -} - -/* Uses the seed to identify an entry in the CAM by looping over all its entries - * Returns the filled in rtl838x_l2_entry and the index in the CAM when an entry was found - * when an empty slot was found the index of the slot is returned - * when no slots are available returns -1 - */ -static int rtldsa_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed, - bool must_exist, struct rtl838x_l2_entry *e) -{ - int idx = -1; - int cam_rows; - u64 entry; - - cam_rows = otto_table_rows(priv->r->l2_cam_tbl); - if (cam_rows < 0) - return -1; - - for (int i = 0; i < cam_rows; i++) { - entry = priv->r->read_cam(i, e); - if (!must_exist && !e->valid) { - if (idx < 0) /* First empty entry? */ - idx = i; - break; - } else if ((entry & 0x0fffffffffffffffULL) == seed) { - pr_debug("Found entry in CAM\n"); - idx = i; - break; - } - } - - return idx; -} - static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, const struct dsa_db db) @@ -901,11 +820,11 @@ static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - idx = rtldsa_find_l2_hash_entry(priv, seed, false, &e); + idx = otto_l2_find_hash_entry(priv, seed, false, &e); /* Found an existing or empty entry */ if (idx >= 0) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, idx); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, idx); if (m) { /* A slot nobody had claimed carries whatever its last @@ -922,7 +841,7 @@ static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port, } /* Hash buckets full, try CAM */ - idx = rtldsa_find_l2_cam_entry(priv, seed, false, &e); + idx = otto_l2_find_cam_entry(priv, seed, false, &e); if (idx >= 0) { rtldsa_setup_l2_uc_entry(&e, port, vid, mac); @@ -956,10 +875,10 @@ static int rtldsa_port_fdb_del(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e); + idx = otto_l2_find_hash_entry(priv, seed, true, &e); if (idx >= 0) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, idx); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, idx); pr_debug("Found entry index %d, key %d and bucket %d\n", idx, idx >> 2, idx & 3); @@ -982,7 +901,7 @@ static int rtldsa_port_fdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - idx = rtldsa_find_l2_cam_entry(priv, seed, true, &e); + idx = otto_l2_find_cam_entry(priv, seed, true, &e); if (idx >= 0) { e.valid = false; @@ -1091,7 +1010,7 @@ static int rtldsa_83xx_port_mdb_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - idx = rtldsa_find_l2_hash_entry(priv, seed, false, &e); + idx = otto_l2_find_hash_entry(priv, seed, false, &e); /* Found an existing or empty entry */ if (idx >= 0) { @@ -1113,7 +1032,7 @@ static int rtldsa_83xx_port_mdb_add(struct dsa_switch *ds, int port, } /* Hash buckets full, try CAM */ - idx = rtldsa_find_l2_cam_entry(priv, seed, false, &e); + idx = otto_l2_find_cam_entry(priv, seed, false, &e); if (idx >= 0) { if (e.valid) { @@ -1177,7 +1096,7 @@ static int rtldsa_port_mdb_del(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e); + idx = otto_l2_find_hash_entry(priv, seed, true, &e); if (idx >= 0) { pr_debug("Found entry index %d, key %d and bucket %d\n", idx, idx >> 2, idx & 3); @@ -1190,7 +1109,7 @@ static int rtldsa_port_mdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - idx = rtldsa_find_l2_cam_entry(priv, seed, true, &e); + idx = otto_l2_find_cam_entry(priv, seed, true, &e); if (idx >= 0) { portmask = rtldsa_mc_group_del_port(priv, e.mc_portmask_index, port); diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.c index 23d984cafbe..2a4f1415193 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "l2.h" #include "l3.h" @@ -56,13 +58,127 @@ #define RTL839X_SPCL_TRAP_ARP_CTRL (0x1060) +int otto_l2_get_ageing_time(struct rtl838x_switch_priv *priv) +{ + int t = sw_r32(priv->r->l2_ctrl_1); + + /* RTL838x uses a high-resolution 23-bit AGE_UNIT where one unit is + * 204.8 ms. RTL839x and RTL93xx use a 21-bit AGE_UNIT where one unit + * is 600 ms. An AGE_UNIT value of 0 disables dynamic address aging. + */ + if (priv->r->high_res_l2_age) { + t &= GENMASK(22, 0); + t = t * 128 / 625; + } else { + t &= GENMASK(20, 0); + t = t * 3 / 5; + } + + pr_debug("L2 AGING time: %d sec\n", t); + pr_debug("Dynamic aging for ports: %x\n", sw_r32(priv->r->l2_port_aging_out)); + + return t; +} + +static int otto_l2_hash_index(u32 key, int slot) +{ + return slot > 3 ? ((key >> 14) & 0xffff) | (slot & 3) : ((key << 2) | slot) & 0xffff; +} + +/* Uses the seed to identify a hash bucket in the L2 using the derived hash key and then loops + * over the entries in the bucket until either a matching entry is found or an empty slot + * Returns the filled in rtl838x_l2_entry and the index in the bucket when an entry was found + * when an empty slot was found and must exist is false, the index of the slot is returned + * when no slots are available returns -1 + */ +int otto_l2_find_hash_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e) +{ + u32 key = priv->r->l2_hash_key(priv, seed); + int free_slot = -1; + u64 entry; + + pr_debug("%s: using key %x, for seed %016llx\n", __func__, key, seed); + /* Loop over all entries in the hash-bucket and over the second block on 93xx SoCs */ + for (int i = 0; i < priv->r->l2_bucket_size; i++) { + entry = priv->r->read_l2_entry_using_hash(key, i, e); + pr_debug("valid %d, mac %016llx\n", e->valid, ether_addr_to_u64(&e->mac[0])); + + /* Remember the first free slot, but keep looking: the address + * may be sitting further down the bucket. + */ + if (!e->valid) { + if (free_slot < 0) + free_slot = i; + continue; + } + + if ((entry & 0x0fffffffffffffffULL) == seed) + return otto_l2_hash_index(key, i); + } + + if (must_exist || free_slot < 0) + return -1; + + /* The loop leaves the last entry it read here, valid bit included. + * Reading the free slot back does not undo that on RTL930x and + * RTL931x, whose readers return as soon as the valid bit is clear. + */ + memset(e, 0, sizeof(*e)); + + return otto_l2_hash_index(key, free_slot); +} + +/* Uses the seed to identify an entry in the CAM by looping over all its entries + * Returns the filled in rtl838x_l2_entry and the index in the CAM when an entry was found + * when an empty slot was found the index of the slot is returned + * when no slots are available returns -1 + */ +int otto_l2_find_cam_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e) +{ + int idx = -1; + int cam_rows; + u64 entry; + + cam_rows = otto_table_rows(priv->r->l2_cam_tbl); + if (cam_rows < 0) + return -1; + + for (int i = 0; i < cam_rows; i++) { + entry = priv->r->read_cam(i, e); + if (!must_exist && !e->valid) { + if (idx < 0) /* First empty entry? */ + idx = i; + break; + } else if ((entry & 0x0fffffffffffffffULL) == seed) { + pr_debug("Found entry in CAM\n"); + idx = i; + break; + } + } + + return idx; +} + +/* RTL931x hashes its second block into rows the fib_entries count does not + * reach, so an index can fall outside the map and is simply not tracked. + */ +struct rtldsa_l2_uc *otto_l2_uc_lookup(struct rtl838x_switch_priv *priv, int idx) +{ + if (idx < 0 || idx >= priv->r->fib_entries) + return NULL; + + return &priv->l2_uc_map[idx]; +} + /* The count pins at its ceiling rather than wrapping: an entry that reached it * is never freed by the driver again, which leaks a row but never hands a live * one to somebody else. */ static void otto_l2_uc_get(struct rtl838x_switch_priv *priv, int idx) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, idx); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, idx); if (!m) return; @@ -77,7 +193,7 @@ static void otto_l2_uc_get(struct rtl838x_switch_priv *priv, int idx) static void otto_l2_uc_put(struct rtl838x_switch_priv *priv, int idx) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, idx); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, idx); if (!m || !m->l3_refcount || m->l3_refcount == RTLDSA_L2_L3_REFCOUNT_MAX) return; @@ -92,7 +208,7 @@ static void otto_l2_uc_release_row(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop *nh, struct rtl838x_l2_entry *e) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, nh->l2_id); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, nh->l2_id); /* Another route is still forwarding through this entry: it has to stay * exactly as it is, next hop and route id included. @@ -126,7 +242,7 @@ static void otto_l2_uc_put_row(struct rtl838x_switch_priv *priv, { struct rtl838x_l2_entry e = {}; - if (rtldsa_find_l2_hash_entry(priv, nh->l2_seed, true, &e) != nh->l2_id) + if (otto_l2_find_hash_entry(priv, nh->l2_seed, true, &e) != nh->l2_id) return; if (!e.next_hop) @@ -157,7 +273,7 @@ int otto_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop */ guard(mutex)(&priv->reg_mutex); - idx = rtldsa_find_l2_hash_entry(priv, seed, false, &e); + idx = otto_l2_find_hash_entry(priv, seed, false, &e); if (idx < 0) { pr_err("%s: No more L2 forwarding entries available\n", __func__); return -1; @@ -183,7 +299,7 @@ int otto_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop otto_l2_uc_put_row(priv, nh); if (!nh->l2_installed || nh->l2_id != idx) { - struct rtldsa_l2_uc *m = rtldsa_l2_uc_lookup(priv, idx); + struct rtldsa_l2_uc *m = otto_l2_uc_lookup(priv, idx); /* An entry nobody had claimed carries whatever its last owner * left behind, including a count for a route long gone. @@ -252,7 +368,7 @@ int otto_l2_nexthop_del(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop * the address that was installed, and it is still the same row. A * negative index means the address has left the bucket altogether. */ - idx = rtldsa_find_l2_hash_entry(priv, nh->l2_seed, true, &e); + idx = otto_l2_find_hash_entry(priv, nh->l2_seed, true, &e); if (idx != nh->l2_id) { dev_err(priv->dev, "next hop %d is at %d now, not removing it\n", nh->l2_id, idx); diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.h index 206ad461d8b..bb3dc16222b 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.h +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l2.h @@ -7,6 +7,7 @@ struct rtl838x_switch_priv; struct rtl838x_l2_entry; +struct rtldsa_l2_uc; struct otto_l3_nexthop; enum rtldsa_flood_type { @@ -58,6 +59,14 @@ enum rtldsa_flood_type { #define RTLDSA_L2_L3_REFCOUNT_MAX 0x7f +/* Returns the L2 ageing time in seconds. */ +int otto_l2_get_ageing_time(struct rtl838x_switch_priv *priv); +int otto_l2_find_hash_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e); +int otto_l2_find_cam_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e); +struct rtldsa_l2_uc *otto_l2_uc_lookup(struct rtl838x_switch_priv *priv, int idx); + int otto_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop *nh, bool require_existing); int otto_l2_nexthop_del(struct rtl838x_switch_priv *priv, struct otto_l3_nexthop *nh); diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h index 3db3c12c5ac..a25f72c0629 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h @@ -611,19 +611,4 @@ extern struct rtl83xx_soc_info soc_info; void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv); void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv); -int rtldsa_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed, - bool must_exist, struct rtl838x_l2_entry *e); - -/* RTL931x hashes its second block into rows the fib_entries count does not - * reach, so an index can fall outside the map and is simply not tracked. - */ -static inline struct rtldsa_l2_uc *rtldsa_l2_uc_lookup(struct rtl838x_switch_priv *priv, - int idx) -{ - if (idx < 0 || idx >= priv->r->fib_entries) - return NULL; - - return &priv->l2_uc_map[idx]; -} - #endif /* _RTL838X_H */