Skip to content

Commit 1b6c215

Browse files
committed
Merge branch 'marvell-prestera-lag'
Vadym Kochan says: ==================== net: marvell: prestera: add LAG support The following features are supported: - LAG basic operations - create/delete LAG - add/remove a member to LAG - enable/disable member in LAG - LAG Bridge support - LAG VLAN support - LAG FDB support Limitations: - Only HASH lag tx type is supported - The Hash parameters are not configurable. They are applied during the LAG creation stage. - Enslaving a port to the LAG device that already has an upper device is not supported. Changes extracted from: https://lkml.org/lkml/2021/2/3/877 and marked with "v2". v2: There are 2 additional preparation patches which simplifies the netdev topology handling. 1) Initialize 'lag' with NULL in prestera_lag_create() [suggested by Vladimir Oltean] 2) Use -ENOSPC in prestera_lag_port_add() if max lag [suggested by Vladimir Oltean] numbers were reached. 3) Do not propagate netdev events to prestera_switchdev [suggested by Vladimir Oltean] but call bridge specific funcs. It simplifies the code. 4) Check on info->link_up in prestera_netdev_port_lower_event() [suggested by Vladimir Oltean] 5) Return -EOPNOTSUPP in prestera_netdev_port_event() in case [suggested by Vladimir Oltean] LAG hashing mode is not supported. 6) Do not pass "lower" netdev to bridge join/leave functions. [suggested by Vladimir Oltean] It is not need as offloading settings applied on particular physical port. It requires to do extra upper dev lookup in case port is in the LAG which is in the bridge on vlans add/del. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 950fd04 + 255213c commit 1b6c215

File tree

6 files changed

+573
-88
lines changed

6 files changed

+573
-88
lines changed

drivers/net/ethernet/marvell/prestera/prestera.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,19 @@ struct prestera_port_caps {
6060
u8 transceiver;
6161
};
6262

63+
struct prestera_lag {
64+
struct net_device *dev;
65+
struct list_head members;
66+
u16 member_count;
67+
u16 lag_id;
68+
};
69+
6370
struct prestera_port {
6471
struct net_device *dev;
6572
struct prestera_switch *sw;
6673
struct devlink_port dl_port;
74+
struct list_head lag_member;
75+
struct prestera_lag *lag;
6776
u32 id;
6877
u32 hw_id;
6978
u32 dev_id;
@@ -127,14 +136,24 @@ struct prestera_port_event {
127136
} data;
128137
};
129138

139+
enum prestera_fdb_entry_type {
140+
PRESTERA_FDB_ENTRY_TYPE_REG_PORT,
141+
PRESTERA_FDB_ENTRY_TYPE_LAG,
142+
PRESTERA_FDB_ENTRY_TYPE_MAX
143+
};
144+
130145
enum prestera_fdb_event_id {
131146
PRESTERA_FDB_EVENT_UNSPEC,
132147
PRESTERA_FDB_EVENT_LEARNED,
133148
PRESTERA_FDB_EVENT_AGED,
134149
};
135150

136151
struct prestera_fdb_event {
137-
u32 port_id;
152+
enum prestera_fdb_entry_type type;
153+
union {
154+
u32 port_id;
155+
u16 lag_id;
156+
} dest;
138157
u32 vid;
139158
union {
140159
u8 mac[ETH_ALEN];
@@ -165,6 +184,9 @@ struct prestera_switch {
165184
u32 mtu_min;
166185
u32 mtu_max;
167186
u8 id;
187+
struct prestera_lag *lags;
188+
u8 lag_member_max;
189+
u8 lag_max;
168190
};
169191

170192
struct prestera_rxtx_params {
@@ -203,4 +225,10 @@ int prestera_port_pvid_set(struct prestera_port *port, u16 vid);
203225

204226
bool prestera_netdev_check(const struct net_device *dev);
205227

228+
bool prestera_port_is_lag_member(const struct prestera_port *port);
229+
230+
struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);
231+
232+
u16 prestera_port_lag_id(const struct prestera_port *port);
233+
206234
#endif /* _PRESTERA_H_ */

drivers/net/ethernet/marvell/prestera/prestera_hw.c

Lines changed: 168 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ enum prestera_cmd_type_t {
4040
PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
4141
PRESTERA_CMD_TYPE_RXTX_PORT_INIT = 0x801,
4242

43+
PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
44+
PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901,
45+
PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902,
46+
PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903,
47+
4348
PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,
4449

4550
PRESTERA_CMD_TYPE_ACK = 0x10000,
@@ -133,6 +138,12 @@ enum {
133138
PRESTERA_FC_SYMM_ASYMM,
134139
};
135140

141+
enum {
142+
PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,
143+
PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,
144+
PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,
145+
};
146+
136147
struct prestera_fw_event_handler {
137148
struct list_head list;
138149
struct rcu_head rcu;
@@ -174,6 +185,8 @@ struct prestera_msg_switch_init_resp {
174185
u32 port_count;
175186
u32 mtu_max;
176187
u8 switch_id;
188+
u8 lag_max;
189+
u8 lag_member_max;
177190
};
178191

179192
struct prestera_msg_port_autoneg_param {
@@ -261,8 +274,13 @@ struct prestera_msg_vlan_req {
261274
struct prestera_msg_fdb_req {
262275
struct prestera_msg_cmd cmd;
263276
u8 dest_type;
264-
u32 port;
265-
u32 dev;
277+
union {
278+
struct {
279+
u32 port;
280+
u32 dev;
281+
};
282+
u16 lag_id;
283+
} dest;
266284
u8 mac[ETH_ALEN];
267285
u16 vid;
268286
u8 dynamic;
@@ -305,6 +323,13 @@ struct prestera_msg_rxtx_port_req {
305323
u32 dev;
306324
};
307325

326+
struct prestera_msg_lag_req {
327+
struct prestera_msg_cmd cmd;
328+
u32 port;
329+
u32 dev;
330+
u16 lag_id;
331+
};
332+
308333
struct prestera_msg_event {
309334
u16 type;
310335
u16 id;
@@ -327,7 +352,10 @@ union prestera_msg_event_fdb_param {
327352
struct prestera_msg_event_fdb {
328353
struct prestera_msg_event id;
329354
u8 dest_type;
330-
u32 port_id;
355+
union {
356+
u32 port_id;
357+
u16 lag_id;
358+
} dest;
331359
u32 vid;
332360
union prestera_msg_event_fdb_param param;
333361
};
@@ -398,7 +426,19 @@ static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt)
398426
{
399427
struct prestera_msg_event_fdb *hw_evt = msg;
400428

401-
evt->fdb_evt.port_id = hw_evt->port_id;
429+
switch (hw_evt->dest_type) {
430+
case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT:
431+
evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT;
432+
evt->fdb_evt.dest.port_id = hw_evt->dest.port_id;
433+
break;
434+
case PRESTERA_HW_FDB_ENTRY_TYPE_LAG:
435+
evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG;
436+
evt->fdb_evt.dest.lag_id = hw_evt->dest.lag_id;
437+
break;
438+
default:
439+
return -EINVAL;
440+
}
441+
402442
evt->fdb_evt.vid = hw_evt->vid;
403443

404444
ether_addr_copy(evt->fdb_evt.data.mac, hw_evt->param.mac);
@@ -543,6 +583,8 @@ int prestera_hw_switch_init(struct prestera_switch *sw)
543583
sw->mtu_min = PRESTERA_MIN_MTU;
544584
sw->mtu_max = resp.mtu_max;
545585
sw->id = resp.switch_id;
586+
sw->lag_member_max = resp.lag_member_max;
587+
sw->lag_max = resp.lag_max;
546588

547589
return 0;
548590
}
@@ -1150,8 +1192,10 @@ int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac,
11501192
u16 vid, bool dynamic)
11511193
{
11521194
struct prestera_msg_fdb_req req = {
1153-
.port = port->hw_id,
1154-
.dev = port->dev_id,
1195+
.dest = {
1196+
.dev = port->dev_id,
1197+
.port = port->hw_id,
1198+
},
11551199
.vid = vid,
11561200
.dynamic = dynamic,
11571201
};
@@ -1166,8 +1210,10 @@ int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
11661210
u16 vid)
11671211
{
11681212
struct prestera_msg_fdb_req req = {
1169-
.port = port->hw_id,
1170-
.dev = port->dev_id,
1213+
.dest = {
1214+
.dev = port->dev_id,
1215+
.port = port->hw_id,
1216+
},
11711217
.vid = vid,
11721218
};
11731219

@@ -1177,11 +1223,48 @@ int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
11771223
&req.cmd, sizeof(req));
11781224
}
11791225

1226+
int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
1227+
const unsigned char *mac, u16 vid, bool dynamic)
1228+
{
1229+
struct prestera_msg_fdb_req req = {
1230+
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1231+
.dest = {
1232+
.lag_id = lag_id,
1233+
},
1234+
.vid = vid,
1235+
.dynamic = dynamic,
1236+
};
1237+
1238+
ether_addr_copy(req.mac, mac);
1239+
1240+
return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_ADD,
1241+
&req.cmd, sizeof(req));
1242+
}
1243+
1244+
int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
1245+
const unsigned char *mac, u16 vid)
1246+
{
1247+
struct prestera_msg_fdb_req req = {
1248+
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1249+
.dest = {
1250+
.lag_id = lag_id,
1251+
},
1252+
.vid = vid,
1253+
};
1254+
1255+
ether_addr_copy(req.mac, mac);
1256+
1257+
return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_DELETE,
1258+
&req.cmd, sizeof(req));
1259+
}
1260+
11801261
int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode)
11811262
{
11821263
struct prestera_msg_fdb_req req = {
1183-
.port = port->hw_id,
1184-
.dev = port->dev_id,
1264+
.dest = {
1265+
.dev = port->dev_id,
1266+
.port = port->hw_id,
1267+
},
11851268
.flush_mode = mode,
11861269
};
11871270

@@ -1204,8 +1287,10 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
12041287
u32 mode)
12051288
{
12061289
struct prestera_msg_fdb_req req = {
1207-
.port = port->hw_id,
1208-
.dev = port->dev_id,
1290+
.dest = {
1291+
.dev = port->dev_id,
1292+
.port = port->hw_id,
1293+
},
12091294
.vid = vid,
12101295
.flush_mode = mode,
12111296
};
@@ -1214,6 +1299,37 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
12141299
&req.cmd, sizeof(req));
12151300
}
12161301

1302+
int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
1303+
u32 mode)
1304+
{
1305+
struct prestera_msg_fdb_req req = {
1306+
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1307+
.dest = {
1308+
.lag_id = lag_id,
1309+
},
1310+
.flush_mode = mode,
1311+
};
1312+
1313+
return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,
1314+
&req.cmd, sizeof(req));
1315+
}
1316+
1317+
int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
1318+
u16 lag_id, u16 vid, u32 mode)
1319+
{
1320+
struct prestera_msg_fdb_req req = {
1321+
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1322+
.dest = {
1323+
.lag_id = lag_id,
1324+
},
1325+
.vid = vid,
1326+
.flush_mode = mode,
1327+
};
1328+
1329+
return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,
1330+
&req.cmd, sizeof(req));
1331+
}
1332+
12171333
int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id)
12181334
{
12191335
struct prestera_msg_bridge_resp resp;
@@ -1295,6 +1411,46 @@ int prestera_hw_rxtx_port_init(struct prestera_port *port)
12951411
&req.cmd, sizeof(req));
12961412
}
12971413

1414+
int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id)
1415+
{
1416+
struct prestera_msg_lag_req req = {
1417+
.port = port->hw_id,
1418+
.dev = port->dev_id,
1419+
.lag_id = lag_id,
1420+
};
1421+
1422+
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_ADD,
1423+
&req.cmd, sizeof(req));
1424+
}
1425+
1426+
int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id)
1427+
{
1428+
struct prestera_msg_lag_req req = {
1429+
.port = port->hw_id,
1430+
.dev = port->dev_id,
1431+
.lag_id = lag_id,
1432+
};
1433+
1434+
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE,
1435+
&req.cmd, sizeof(req));
1436+
}
1437+
1438+
int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
1439+
bool enable)
1440+
{
1441+
struct prestera_msg_lag_req req = {
1442+
.port = port->hw_id,
1443+
.dev = port->dev_id,
1444+
.lag_id = lag_id,
1445+
};
1446+
u32 cmd;
1447+
1448+
cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE :
1449+
PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE;
1450+
1451+
return prestera_cmd(port->sw, cmd, &req.cmd, sizeof(req));
1452+
}
1453+
12981454
int prestera_hw_event_handler_register(struct prestera_switch *sw,
12991455
enum prestera_event_type type,
13001456
prestera_event_cb_t fn,

drivers/net/ethernet/marvell/prestera/prestera_hw.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,18 @@ int prestera_hw_rxtx_init(struct prestera_switch *sw,
180180
struct prestera_rxtx_params *params);
181181
int prestera_hw_rxtx_port_init(struct prestera_port *port);
182182

183+
/* LAG API */
184+
int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id);
185+
int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id);
186+
int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
187+
bool enable);
188+
int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
189+
const unsigned char *mac, u16 vid, bool dynamic);
190+
int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
191+
const unsigned char *mac, u16 vid);
192+
int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
193+
u32 mode);
194+
int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
195+
u16 lag_id, u16 vid, u32 mode);
196+
183197
#endif /* _PRESTERA_HW_H_ */

0 commit comments

Comments
 (0)