Skip to content

Commit e09ce97

Browse files
HoratiuVulturdavem330
authored andcommitted
net: lan966x: Extend MAC to support also lag interfaces.
Extend MAC support to support also lag interfaces: 1. In case an entry is learned on a port that is part of lag interface, then notify the upper layers that the entry is learned on the bond interface 2. If a port leaves the bond and the port is the first port in the lag group, then it is required to update all MAC entries to change the destination port. Signed-off-by: Horatiu Vultur <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9be99f2 commit e09ce97

File tree

3 files changed

+119
-16
lines changed

3 files changed

+119
-16
lines changed

drivers/net/ethernet/microchip/lan966x/lan966x_lag.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,14 @@ int lan966x_lag_port_join(struct lan966x_port *port,
123123
{
124124
struct lan966x *lan966x = port->lan966x;
125125
struct net_device *dev = port->dev;
126+
u32 lag_id = -1;
127+
u32 bond_mask;
126128
int err;
127129

130+
bond_mask = lan966x_lag_get_mask(lan966x, bond);
131+
if (bond_mask)
132+
lag_id = __ffs(bond_mask);
133+
128134
port->bond = bond;
129135
lan966x_lag_update_ids(lan966x);
130136

@@ -137,6 +143,12 @@ int lan966x_lag_port_join(struct lan966x_port *port,
137143

138144
lan966x_port_stp_state_set(port, br_port_get_stp_state(brport_dev));
139145

146+
if (lan966x_lag_first_port(port->bond, port->dev) &&
147+
lag_id != -1)
148+
lan966x_mac_lag_replace_port_entry(lan966x,
149+
lan966x->ports[lag_id],
150+
port);
151+
140152
return 0;
141153

142154
out:
@@ -149,6 +161,20 @@ int lan966x_lag_port_join(struct lan966x_port *port,
149161
void lan966x_lag_port_leave(struct lan966x_port *port, struct net_device *bond)
150162
{
151163
struct lan966x *lan966x = port->lan966x;
164+
u32 bond_mask;
165+
u32 lag_id;
166+
167+
if (lan966x_lag_first_port(port->bond, port->dev)) {
168+
bond_mask = lan966x_lag_get_mask(lan966x, port->bond);
169+
bond_mask &= ~BIT(port->chip_port);
170+
if (bond_mask) {
171+
lag_id = __ffs(bond_mask);
172+
lan966x_mac_lag_replace_port_entry(lan966x, port,
173+
lan966x->ports[lag_id]);
174+
} else {
175+
lan966x_mac_lag_remove_port_entry(lan966x, port);
176+
}
177+
}
152178

153179
port->bond = NULL;
154180
lan966x_lag_update_ids(lan966x);

drivers/net/ethernet/microchip/lan966x/lan966x_mac.c

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct lan966x_mac_entry {
2222
u16 vid;
2323
u16 port_index;
2424
int row;
25+
bool lag;
2526
};
2627

2728
struct lan966x_mac_raw_entry {
@@ -69,15 +70,14 @@ static void lan966x_mac_select(struct lan966x *lan966x,
6970
lan_wr(mach, lan966x, ANA_MACHDATA);
7071
}
7172

72-
static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
73-
bool cpu_copy,
74-
const unsigned char mac[ETH_ALEN],
75-
unsigned int vid,
76-
enum macaccess_entry_type type)
73+
static int __lan966x_mac_learn_locked(struct lan966x *lan966x, int pgid,
74+
bool cpu_copy,
75+
const unsigned char mac[ETH_ALEN],
76+
unsigned int vid,
77+
enum macaccess_entry_type type)
7778
{
78-
int ret;
79+
lockdep_assert_held(&lan966x->mac_lock);
7980

80-
spin_lock(&lan966x->mac_lock);
8181
lan966x_mac_select(lan966x, mac, vid);
8282

8383
/* Issue a write command */
@@ -89,7 +89,19 @@ static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
8989
ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
9090
lan966x, ANA_MACACCESS);
9191

92-
ret = lan966x_mac_wait_for_completion(lan966x);
92+
return lan966x_mac_wait_for_completion(lan966x);
93+
}
94+
95+
static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
96+
bool cpu_copy,
97+
const unsigned char mac[ETH_ALEN],
98+
unsigned int vid,
99+
enum macaccess_entry_type type)
100+
{
101+
int ret;
102+
103+
spin_lock(&lan966x->mac_lock);
104+
ret = __lan966x_mac_learn_locked(lan966x, pgid, cpu_copy, mac, vid, type);
93105
spin_unlock(&lan966x->mac_lock);
94106

95107
return ret;
@@ -119,6 +131,16 @@ int lan966x_mac_learn(struct lan966x *lan966x, int port,
119131
return __lan966x_mac_learn(lan966x, port, false, mac, vid, type);
120132
}
121133

134+
static int lan966x_mac_learn_locked(struct lan966x *lan966x, int port,
135+
const unsigned char mac[ETH_ALEN],
136+
unsigned int vid,
137+
enum macaccess_entry_type type)
138+
{
139+
WARN_ON(type != ENTRYTYPE_NORMAL && type != ENTRYTYPE_LOCKED);
140+
141+
return __lan966x_mac_learn_locked(lan966x, port, false, mac, vid, type);
142+
}
143+
122144
static int lan966x_mac_forget_locked(struct lan966x *lan966x,
123145
const unsigned char mac[ETH_ALEN],
124146
unsigned int vid,
@@ -178,8 +200,9 @@ void lan966x_mac_init(struct lan966x *lan966x)
178200
INIT_LIST_HEAD(&lan966x->mac_entries);
179201
}
180202

181-
static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *mac,
182-
u16 vid, u16 port_index)
203+
static struct lan966x_mac_entry *lan966x_mac_alloc_entry(struct lan966x_port *port,
204+
const unsigned char *mac,
205+
u16 vid)
183206
{
184207
struct lan966x_mac_entry *mac_entry;
185208

@@ -189,8 +212,9 @@ static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *ma
189212

190213
memcpy(mac_entry->mac, mac, ETH_ALEN);
191214
mac_entry->vid = vid;
192-
mac_entry->port_index = port_index;
215+
mac_entry->port_index = port->chip_port;
193216
mac_entry->row = LAN966X_MAC_INVALID_ROW;
217+
mac_entry->lag = port->bond ? true : false;
194218
return mac_entry;
195219
}
196220

@@ -269,7 +293,7 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
269293
goto mac_learn;
270294
}
271295

272-
mac_entry = lan966x_mac_alloc_entry(addr, vid, port->chip_port);
296+
mac_entry = lan966x_mac_alloc_entry(port, addr, vid);
273297
if (!mac_entry) {
274298
spin_unlock(&lan966x->mac_lock);
275299
return -ENOMEM;
@@ -278,7 +302,8 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
278302
list_add_tail(&mac_entry->list, &lan966x->mac_entries);
279303
spin_unlock(&lan966x->mac_lock);
280304

281-
lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid, port->dev);
305+
lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid,
306+
port->bond ?: port->dev);
282307

283308
mac_learn:
284309
lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
@@ -309,6 +334,50 @@ int lan966x_mac_del_entry(struct lan966x *lan966x, const unsigned char *addr,
309334
return 0;
310335
}
311336

337+
void lan966x_mac_lag_replace_port_entry(struct lan966x *lan966x,
338+
struct lan966x_port *src,
339+
struct lan966x_port *dst)
340+
{
341+
struct lan966x_mac_entry *mac_entry;
342+
343+
spin_lock(&lan966x->mac_lock);
344+
list_for_each_entry(mac_entry, &lan966x->mac_entries, list) {
345+
if (mac_entry->port_index == src->chip_port &&
346+
mac_entry->lag) {
347+
lan966x_mac_forget_locked(lan966x, mac_entry->mac,
348+
mac_entry->vid,
349+
ENTRYTYPE_LOCKED);
350+
351+
lan966x_mac_learn_locked(lan966x, dst->chip_port,
352+
mac_entry->mac, mac_entry->vid,
353+
ENTRYTYPE_LOCKED);
354+
mac_entry->port_index = dst->chip_port;
355+
}
356+
}
357+
spin_unlock(&lan966x->mac_lock);
358+
}
359+
360+
void lan966x_mac_lag_remove_port_entry(struct lan966x *lan966x,
361+
struct lan966x_port *src)
362+
{
363+
struct lan966x_mac_entry *mac_entry, *tmp;
364+
365+
spin_lock(&lan966x->mac_lock);
366+
list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
367+
list) {
368+
if (mac_entry->port_index == src->chip_port &&
369+
mac_entry->lag) {
370+
lan966x_mac_forget_locked(lan966x, mac_entry->mac,
371+
mac_entry->vid,
372+
ENTRYTYPE_LOCKED);
373+
374+
list_del(&mac_entry->list);
375+
kfree(mac_entry);
376+
}
377+
}
378+
spin_unlock(&lan966x->mac_lock);
379+
}
380+
312381
void lan966x_mac_purge_entries(struct lan966x *lan966x)
313382
{
314383
struct lan966x_mac_entry *mac_entry, *tmp;
@@ -354,6 +423,7 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
354423
struct lan966x_mac_entry *mac_entry, *tmp;
355424
unsigned char mac[ETH_ALEN] __aligned(2);
356425
struct list_head mac_deleted_entries;
426+
struct lan966x_port *port;
357427
u32 dest_idx;
358428
u32 column;
359429
u16 vid;
@@ -406,9 +476,10 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
406476
/* Notify the bridge that the entry doesn't exist
407477
* anymore in the HW
408478
*/
479+
port = lan966x->ports[mac_entry->port_index];
409480
lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
410481
mac_entry->mac, mac_entry->vid,
411-
lan966x->ports[mac_entry->port_index]->dev);
482+
port->bond ?: port->dev);
412483
list_del(&mac_entry->list);
413484
kfree(mac_entry);
414485
}
@@ -440,7 +511,8 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
440511
continue;
441512
}
442513

443-
mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
514+
port = lan966x->ports[dest_idx];
515+
mac_entry = lan966x_mac_alloc_entry(port, mac, vid);
444516
if (!mac_entry) {
445517
spin_unlock(&lan966x->mac_lock);
446518
return;
@@ -451,7 +523,7 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
451523
spin_unlock(&lan966x->mac_lock);
452524

453525
lan966x_mac_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
454-
mac, vid, lan966x->ports[dest_idx]->dev);
526+
mac, vid, port->bond ?: port->dev);
455527
}
456528
}
457529

drivers/net/ethernet/microchip/lan966x/lan966x_main.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ int lan966x_mac_add_entry(struct lan966x *lan966x,
351351
struct lan966x_port *port,
352352
const unsigned char *addr,
353353
u16 vid);
354+
void lan966x_mac_lag_replace_port_entry(struct lan966x *lan966x,
355+
struct lan966x_port *src,
356+
struct lan966x_port *dst);
357+
void lan966x_mac_lag_remove_port_entry(struct lan966x *lan966x,
358+
struct lan966x_port *src);
354359
void lan966x_mac_purge_entries(struct lan966x *lan966x);
355360
irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x);
356361

0 commit comments

Comments
 (0)