1 From c45655386e532c85ff1d679fc2aa40b3aaff9916 Mon Sep 17 00:00:00 2001
2 From: Florian Fainelli <f.fainelli@gmail.com>
3 Date: Sat, 14 Jun 2025 09:59:51 +0200
4 Subject: [PATCH] net: dsa: b53: add support for FDB operations on 5325/5365
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 BCM5325 and BCM5365 are part of a much older generation of switches which,
10 due to their limited number of ports and VLAN entries (up to 256) allowed
11 a single 64-bit register to hold a full ARL entry.
12 This requires a little bit of massaging when reading, writing and
13 converting ARL entries in both directions.
15 Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
16 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
17 Link: https://patch.msgid.link/20250614080000.1884236-6-noltari@gmail.com
18 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
20 drivers/net/dsa/b53/b53_common.c | 101 +++++++++++++++++++++++++------
21 drivers/net/dsa/b53/b53_priv.h | 29 +++++++++
22 drivers/net/dsa/b53/b53_regs.h | 7 ++-
23 3 files changed, 115 insertions(+), 22 deletions(-)
25 --- a/drivers/net/dsa/b53/b53_common.c
26 +++ b/drivers/net/dsa/b53/b53_common.c
27 @@ -1802,6 +1802,45 @@ static int b53_arl_read(struct b53_devic
28 return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
31 +static int b53_arl_read_25(struct b53_device *dev, u64 mac,
32 + u16 vid, struct b53_arl_entry *ent, u8 *idx)
34 + DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
38 + ret = b53_arl_op_wait(dev);
42 + bitmap_zero(free_bins, dev->num_arl_bins);
45 + for (i = 0; i < dev->num_arl_bins; i++) {
48 + b53_read64(dev, B53_ARLIO_PAGE,
49 + B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
51 + b53_arl_to_entry_25(ent, mac_vid);
53 + if (!(mac_vid & ARLTBL_VALID_25)) {
54 + set_bit(i, free_bins);
57 + if ((mac_vid & ARLTBL_MAC_MASK) != mac)
59 + if (dev->vlan_enabled &&
60 + ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid)
66 + *idx = find_first_bit(free_bins, dev->num_arl_bins);
67 + return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
70 static int b53_arl_op(struct b53_device *dev, int op, int port,
71 const unsigned char *addr, u16 vid, bool is_valid)
73 @@ -1824,7 +1863,10 @@ static int b53_arl_op(struct b53_device
77 - ret = b53_arl_read(dev, mac, vid, &ent, &idx);
78 + if (is5325(dev) || is5365(dev))
79 + ret = b53_arl_read_25(dev, mac, vid, &ent, &idx);
81 + ret = b53_arl_read(dev, mac, vid, &ent, &idx);
83 /* If this is a read, just finish now */
85 @@ -1868,12 +1910,17 @@ static int b53_arl_op(struct b53_device
88 memcpy(ent.mac, addr, ETH_ALEN);
89 - b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
90 + if (is5325(dev) || is5365(dev))
91 + b53_arl_from_entry_25(&mac_vid, &ent);
93 + b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
95 b53_write64(dev, B53_ARLIO_PAGE,
96 B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);
97 - b53_write32(dev, B53_ARLIO_PAGE,
98 - B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
100 + if (!is5325(dev) && !is5365(dev))
101 + b53_write32(dev, B53_ARLIO_PAGE,
102 + B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
104 return b53_arl_rw_op(dev, 0);
106 @@ -1885,12 +1932,6 @@ int b53_fdb_add(struct dsa_switch *ds, i
107 struct b53_device *priv = ds->priv;
110 - /* 5325 and 5365 require some more massaging, but could
111 - * be supported eventually
113 - if (is5325(priv) || is5365(priv))
114 - return -EOPNOTSUPP;
116 mutex_lock(&priv->arl_mutex);
117 ret = b53_arl_op(priv, 0, port, addr, vid, true);
118 mutex_unlock(&priv->arl_mutex);
119 @@ -1917,10 +1958,15 @@ EXPORT_SYMBOL(b53_fdb_del);
120 static int b53_arl_search_wait(struct b53_device *dev)
122 unsigned int timeout = 1000;
126 + if (is5325(dev) || is5365(dev))
127 + offset = B53_ARL_SRCH_CTL_25;
129 + offset = B53_ARL_SRCH_CTL;
132 - b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, ®);
133 + b53_read8(dev, B53_ARLIO_PAGE, offset, ®);
134 if (!(reg & ARL_SRCH_STDN))
137 @@ -1937,13 +1983,24 @@ static void b53_arl_search_rd(struct b53
138 struct b53_arl_entry *ent)
143 - b53_read64(dev, B53_ARLIO_PAGE,
144 - B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid);
145 - b53_read32(dev, B53_ARLIO_PAGE,
146 - B53_ARL_SRCH_RSTL(idx), &fwd_entry);
147 - b53_arl_to_entry(ent, mac_vid, fwd_entry);
149 + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25,
151 + b53_arl_to_entry_25(ent, mac_vid);
152 + } else if (is5365(dev)) {
153 + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65,
155 + b53_arl_to_entry_25(ent, mac_vid);
159 + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx),
161 + b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx),
163 + b53_arl_to_entry(ent, mac_vid, fwd_entry);
167 static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
168 @@ -1964,14 +2021,20 @@ int b53_fdb_dump(struct dsa_switch *ds,
169 struct b53_device *priv = ds->priv;
170 struct b53_arl_entry results[2];
171 unsigned int count = 0;
176 mutex_lock(&priv->arl_mutex);
178 + if (is5325(priv) || is5365(priv))
179 + offset = B53_ARL_SRCH_CTL_25;
181 + offset = B53_ARL_SRCH_CTL;
183 /* Start search operation */
185 - b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg);
186 + b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg);
189 ret = b53_arl_search_wait(priv);
190 --- a/drivers/net/dsa/b53/b53_priv.h
191 +++ b/drivers/net/dsa/b53/b53_priv.h
192 @@ -317,6 +317,19 @@ static inline void b53_arl_to_entry(stru
193 ent->vid = mac_vid >> ARLTBL_VID_S;
196 +static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent,
199 + memset(ent, 0, sizeof(*ent));
200 + ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) &
201 + ARLTBL_DATA_PORT_ID_MASK_25;
202 + ent->is_valid = !!(mac_vid & ARLTBL_VALID_25);
203 + ent->is_age = !!(mac_vid & ARLTBL_AGE_25);
204 + ent->is_static = !!(mac_vid & ARLTBL_STATIC_25);
205 + u64_to_ether_addr(mac_vid, ent->mac);
206 + ent->vid = mac_vid >> ARLTBL_VID_S_65;
209 static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
210 const struct b53_arl_entry *ent)
212 @@ -331,6 +344,22 @@ static inline void b53_arl_from_entry(u6
213 *fwd_entry |= ARLTBL_AGE;
216 +static inline void b53_arl_from_entry_25(u64 *mac_vid,
217 + const struct b53_arl_entry *ent)
219 + *mac_vid = ether_addr_to_u64(ent->mac);
220 + *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) <<
221 + ARLTBL_DATA_PORT_ID_S_25;
222 + *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) <<
225 + *mac_vid |= ARLTBL_VALID_25;
226 + if (ent->is_static)
227 + *mac_vid |= ARLTBL_STATIC_25;
229 + *mac_vid |= ARLTBL_AGE_25;
232 #ifdef CONFIG_BCM47XX
234 #include <linux/bcm47xx_nvram.h>
235 --- a/drivers/net/dsa/b53/b53_regs.h
236 +++ b/drivers/net/dsa/b53/b53_regs.h
238 #define ARLTBL_VID_MASK 0xfff
239 #define ARLTBL_DATA_PORT_ID_S_25 48
240 #define ARLTBL_DATA_PORT_ID_MASK_25 0xf
241 -#define ARLTBL_AGE_25 BIT(61)
242 -#define ARLTBL_STATIC_25 BIT(62)
243 -#define ARLTBL_VALID_25 BIT(63)
244 +#define ARLTBL_VID_S_65 53
245 +#define ARLTBL_AGE_25 BIT_ULL(61)
246 +#define ARLTBL_STATIC_25 BIT_ULL(62)
247 +#define ARLTBL_VALID_25 BIT_ULL(63)
249 /* ARL Table Data Entry N Registers (32 bit) */
250 #define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18)