Skip to content

Commit 255213c

Browse files
SerhiyBoikoPLVdavem330
authored andcommitted
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. Co-developed-by: Andrii Savka <[email protected]> Signed-off-by: Andrii Savka <[email protected]> Signed-off-by: Serhiy Boiko <[email protected]> Co-developed-by: Vadym Kochan <[email protected]> Signed-off-by: Vadym Kochan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 82bbaa0 commit 255213c

File tree

5 files changed

+531
-31
lines changed

5 files changed

+531
-31
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)