1 // SPDX-License-Identifier: GPL-2.0+
3 #include <net/switchdev.h>
4 #include "lan966x_main.h"
6 #define LAN966X_MAC_COLUMNS 4
7 #define MACACCESS_CMD_IDLE 0
8 #define MACACCESS_CMD_LEARN 1
9 #define MACACCESS_CMD_FORGET 2
10 #define MACACCESS_CMD_AGE 3
11 #define MACACCESS_CMD_GET_NEXT 4
12 #define MACACCESS_CMD_INIT 5
13 #define MACACCESS_CMD_READ 6
14 #define MACACCESS_CMD_WRITE 7
15 #define MACACCESS_CMD_SYNC_GET_NEXT 8
17 #define LAN966X_MAC_INVALID_ROW -1
19 struct lan966x_mac_entry {
20 struct list_head list;
21 unsigned char mac[ETH_ALEN] __aligned(2);
27 struct lan966x_mac_raw_entry {
34 static int lan966x_mac_get_status(struct lan966x *lan966x)
36 return lan_rd(lan966x, ANA_MACACCESS);
39 static int lan966x_mac_wait_for_completion(struct lan966x *lan966x)
43 return readx_poll_timeout(lan966x_mac_get_status,
45 (ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
47 TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
50 static void lan966x_mac_select(struct lan966x *lan966x,
51 const unsigned char mac[ETH_ALEN],
54 u32 macl = 0, mach = 0;
56 /* Set the MAC address to handle and the vlan associated in a format
57 * understood by the hardware.
67 lan_wr(macl, lan966x, ANA_MACLDATA);
68 lan_wr(mach, lan966x, ANA_MACHDATA);
71 static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
73 const unsigned char mac[ETH_ALEN],
75 enum macaccess_entry_type type)
77 lan966x_mac_select(lan966x, mac, vid);
79 /* Issue a write command */
80 lan_wr(ANA_MACACCESS_VALID_SET(1) |
81 ANA_MACACCESS_CHANGE2SW_SET(0) |
82 ANA_MACACCESS_MAC_CPU_COPY_SET(cpu_copy) |
83 ANA_MACACCESS_DEST_IDX_SET(pgid) |
84 ANA_MACACCESS_ENTRYTYPE_SET(type) |
85 ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
86 lan966x, ANA_MACACCESS);
88 return lan966x_mac_wait_for_completion(lan966x);
91 /* The mask of the front ports is encoded inside the mac parameter via a call
92 * to lan966x_mdb_encode_mac().
94 int lan966x_mac_ip_learn(struct lan966x *lan966x,
96 const unsigned char mac[ETH_ALEN],
98 enum macaccess_entry_type type)
100 WARN_ON(type != ENTRYTYPE_MACV4 && type != ENTRYTYPE_MACV6);
102 return __lan966x_mac_learn(lan966x, 0, cpu_copy, mac, vid, type);
105 int lan966x_mac_learn(struct lan966x *lan966x, int port,
106 const unsigned char mac[ETH_ALEN],
108 enum macaccess_entry_type type)
110 WARN_ON(type != ENTRYTYPE_NORMAL && type != ENTRYTYPE_LOCKED);
112 return __lan966x_mac_learn(lan966x, port, false, mac, vid, type);
115 int lan966x_mac_forget(struct lan966x *lan966x,
116 const unsigned char mac[ETH_ALEN],
118 enum macaccess_entry_type type)
120 lan966x_mac_select(lan966x, mac, vid);
122 /* Issue a forget command */
123 lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
124 ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_FORGET),
125 lan966x, ANA_MACACCESS);
127 return lan966x_mac_wait_for_completion(lan966x);
130 int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid)
132 return lan966x_mac_learn(lan966x, PGID_CPU, addr, vid, ENTRYTYPE_LOCKED);
135 int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid)
137 return lan966x_mac_forget(lan966x, addr, vid, ENTRYTYPE_LOCKED);
140 void lan966x_mac_set_ageing(struct lan966x *lan966x,
143 lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ageing / 2),
144 ANA_AUTOAGE_AGE_PERIOD,
145 lan966x, ANA_AUTOAGE);
148 void lan966x_mac_init(struct lan966x *lan966x)
150 /* Clear the MAC table */
151 lan_wr(MACACCESS_CMD_INIT, lan966x, ANA_MACACCESS);
152 lan966x_mac_wait_for_completion(lan966x);
154 spin_lock_init(&lan966x->mac_lock);
155 INIT_LIST_HEAD(&lan966x->mac_entries);
158 static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *mac,
159 u16 vid, u16 port_index)
161 struct lan966x_mac_entry *mac_entry;
163 mac_entry = kzalloc(sizeof(*mac_entry), GFP_KERNEL);
167 memcpy(mac_entry->mac, mac, ETH_ALEN);
168 mac_entry->vid = vid;
169 mac_entry->port_index = port_index;
170 mac_entry->row = LAN966X_MAC_INVALID_ROW;
174 static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
175 const unsigned char *mac,
176 u16 vid, u16 port_index)
178 struct lan966x_mac_entry *res = NULL;
179 struct lan966x_mac_entry *mac_entry;
181 spin_lock(&lan966x->mac_lock);
182 list_for_each_entry(mac_entry, &lan966x->mac_entries, list) {
183 if (mac_entry->vid == vid &&
184 ether_addr_equal(mac, mac_entry->mac) &&
185 mac_entry->port_index == port_index) {
190 spin_unlock(&lan966x->mac_lock);
195 static int lan966x_mac_lookup(struct lan966x *lan966x,
196 const unsigned char mac[ETH_ALEN],
197 unsigned int vid, enum macaccess_entry_type type)
201 lan966x_mac_select(lan966x, mac, vid);
203 /* Issue a read command */
204 lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
205 ANA_MACACCESS_VALID_SET(1) |
206 ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_READ),
207 lan966x, ANA_MACACCESS);
209 ret = lan966x_mac_wait_for_completion(lan966x);
213 return ANA_MACACCESS_VALID_GET(lan_rd(lan966x, ANA_MACACCESS));
216 static void lan966x_fdb_call_notifiers(enum switchdev_notifier_type type,
217 const char *mac, u16 vid,
218 struct net_device *dev)
220 struct switchdev_notifier_fdb_info info = { 0 };
224 info.offloaded = true;
225 call_switchdev_notifiers(type, dev, &info.info, NULL);
228 int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
229 const unsigned char *addr, u16 vid)
231 struct lan966x_mac_entry *mac_entry;
233 if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL))
236 /* In case the entry already exists, don't add it again to SW,
237 * just update HW, but we need to look in the actual HW because
238 * it is possible for an entry to be learn by HW and before we
239 * get the interrupt the frame will reach CPU and the CPU will
240 * add the entry but without the extern_learn flag.
242 mac_entry = lan966x_mac_find_entry(lan966x, addr, vid, port->chip_port);
244 return lan966x_mac_learn(lan966x, port->chip_port,
245 addr, vid, ENTRYTYPE_LOCKED);
247 mac_entry = lan966x_mac_alloc_entry(addr, vid, port->chip_port);
251 spin_lock(&lan966x->mac_lock);
252 list_add_tail(&mac_entry->list, &lan966x->mac_entries);
253 spin_unlock(&lan966x->mac_lock);
255 lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
256 lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid, port->dev);
261 int lan966x_mac_del_entry(struct lan966x *lan966x, const unsigned char *addr,
264 struct lan966x_mac_entry *mac_entry, *tmp;
266 spin_lock(&lan966x->mac_lock);
267 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
269 if (mac_entry->vid == vid &&
270 ether_addr_equal(addr, mac_entry->mac)) {
271 lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
274 list_del(&mac_entry->list);
278 spin_unlock(&lan966x->mac_lock);
283 void lan966x_mac_purge_entries(struct lan966x *lan966x)
285 struct lan966x_mac_entry *mac_entry, *tmp;
287 spin_lock(&lan966x->mac_lock);
288 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
290 lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
293 list_del(&mac_entry->list);
296 spin_unlock(&lan966x->mac_lock);
299 static void lan966x_mac_notifiers(enum switchdev_notifier_type type,
300 unsigned char *mac, u32 vid,
301 struct net_device *dev)
304 lan966x_fdb_call_notifiers(type, mac, vid, dev);
308 static void lan966x_mac_process_raw_entry(struct lan966x_mac_raw_entry *raw_entry,
309 u8 *mac, u16 *vid, u32 *dest_idx)
311 mac[0] = (raw_entry->mach >> 8) & 0xff;
312 mac[1] = (raw_entry->mach >> 0) & 0xff;
313 mac[2] = (raw_entry->macl >> 24) & 0xff;
314 mac[3] = (raw_entry->macl >> 16) & 0xff;
315 mac[4] = (raw_entry->macl >> 8) & 0xff;
316 mac[5] = (raw_entry->macl >> 0) & 0xff;
318 *vid = (raw_entry->mach >> 16) & 0xfff;
319 *dest_idx = ANA_MACACCESS_DEST_IDX_GET(raw_entry->maca);
322 static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
323 struct lan966x_mac_raw_entry *raw_entries)
325 struct lan966x_mac_entry *mac_entry, *tmp;
326 unsigned char mac[ETH_ALEN] __aligned(2);
331 spin_lock(&lan966x->mac_lock);
332 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries, list) {
335 if (mac_entry->row != row)
338 for (column = 0; column < LAN966X_MAC_COLUMNS; ++column) {
339 /* All the valid entries are at the start of the row,
340 * so when get one invalid entry it can just skip the
341 * rest of the columns
343 if (!ANA_MACACCESS_VALID_GET(raw_entries[column].maca))
346 lan966x_mac_process_raw_entry(&raw_entries[column],
347 mac, &vid, &dest_idx);
348 WARN_ON(dest_idx > lan966x->num_phys_ports);
350 /* If the entry in SW is found, then there is nothing
353 if (mac_entry->vid == vid &&
354 ether_addr_equal(mac_entry->mac, mac) &&
355 mac_entry->port_index == dest_idx) {
356 raw_entries[column].processed = true;
363 /* Notify the bridge that the entry doesn't exist
364 * anymore in the HW and remove the entry from the SW
367 lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
368 mac_entry->mac, mac_entry->vid,
369 lan966x->ports[mac_entry->port_index]->dev);
371 list_del(&mac_entry->list);
375 spin_unlock(&lan966x->mac_lock);
377 /* Now go to the list of columns and see if any entry was not in the SW
378 * list, then that means that the entry is new so it needs to notify the
381 for (column = 0; column < LAN966X_MAC_COLUMNS; ++column) {
382 /* All the valid entries are at the start of the row, so when
383 * get one invalid entry it can just skip the rest of the columns
385 if (!ANA_MACACCESS_VALID_GET(raw_entries[column].maca))
388 /* If the entry already exists then don't do anything */
389 if (raw_entries[column].processed)
392 lan966x_mac_process_raw_entry(&raw_entries[column],
393 mac, &vid, &dest_idx);
394 WARN_ON(dest_idx > lan966x->num_phys_ports);
396 mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
400 mac_entry->row = row;
402 spin_lock(&lan966x->mac_lock);
403 list_add_tail(&mac_entry->list, &lan966x->mac_entries);
404 spin_unlock(&lan966x->mac_lock);
406 lan966x_mac_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
407 mac, vid, lan966x->ports[dest_idx]->dev);
411 irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x)
413 struct lan966x_mac_raw_entry entry[LAN966X_MAC_COLUMNS] = { 0 };
418 /* Start the scan from 0, 0 */
419 lan_wr(ANA_MACTINDX_M_INDEX_SET(0) |
420 ANA_MACTINDX_BUCKET_SET(0),
421 lan966x, ANA_MACTINDX);
424 lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),
425 ANA_MACACCESS_MAC_TABLE_CMD,
426 lan966x, ANA_MACACCESS);
427 lan966x_mac_wait_for_completion(lan966x);
429 val = lan_rd(lan966x, ANA_MACTINDX);
430 index = ANA_MACTINDX_M_INDEX_GET(val);
431 column = ANA_MACTINDX_BUCKET_GET(val);
433 /* The SYNC-GET-NEXT returns all the entries(4) in a row in
434 * which is suffered a change. By change it means that new entry
435 * was added or an entry was removed because of ageing.
436 * It would return all the columns for that row. And after that
437 * it would return the next row The stop conditions of the
438 * SYNC-GET-NEXT is when it reaches 'directly' to row 0
439 * column 3. So if SYNC-GET-NEXT returns row 0 and column 0
440 * then it is required to continue to read more even if it
441 * reaches row 0 and column 3.
443 if (index == 0 && column == 0)
446 if (column == LAN966X_MAC_COLUMNS - 1 &&
450 entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);
451 entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);
452 entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);
454 /* Once all the columns are read process them */
455 if (column == LAN966X_MAC_COLUMNS - 1) {
456 lan966x_mac_irq_process(lan966x, index, entry);
457 /* A row was processed so it is safe to assume that the
458 * next row/column can be the stop condition
464 lan_rmw(ANA_ANAINTR_INTR_SET(0),
466 lan966x, ANA_ANAINTR);