Skip to content

Commit

Permalink
net: marvell: prestera: add LAG support
Browse files Browse the repository at this point in the history
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 <andrii.savka@plvision.eu>
Signed-off-by: Andrii Savka <andrii.savka@plvision.eu>
Signed-off-by: Serhiy Boiko <serhiy.boiko@plvision.eu>
Co-developed-by: Vadym Kochan <vkochan@marvell.com>
Signed-off-by: Vadym Kochan <vkochan@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Serhiy Boiko authored and David S. Miller committed Jun 10, 2021
1 parent 82bbaa0 commit 255213c
Show file tree
Hide file tree
Showing 5 changed files with 531 additions and 31 deletions.
30 changes: 29 additions & 1 deletion drivers/net/ethernet/marvell/prestera/prestera.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,19 @@ struct prestera_port_caps {
u8 transceiver;
};

struct prestera_lag {
struct net_device *dev;
struct list_head members;
u16 member_count;
u16 lag_id;
};

struct prestera_port {
struct net_device *dev;
struct prestera_switch *sw;
struct devlink_port dl_port;
struct list_head lag_member;
struct prestera_lag *lag;
u32 id;
u32 hw_id;
u32 dev_id;
Expand Down Expand Up @@ -127,14 +136,24 @@ struct prestera_port_event {
} data;
};

enum prestera_fdb_entry_type {
PRESTERA_FDB_ENTRY_TYPE_REG_PORT,
PRESTERA_FDB_ENTRY_TYPE_LAG,
PRESTERA_FDB_ENTRY_TYPE_MAX
};

enum prestera_fdb_event_id {
PRESTERA_FDB_EVENT_UNSPEC,
PRESTERA_FDB_EVENT_LEARNED,
PRESTERA_FDB_EVENT_AGED,
};

struct prestera_fdb_event {
u32 port_id;
enum prestera_fdb_entry_type type;
union {
u32 port_id;
u16 lag_id;
} dest;
u32 vid;
union {
u8 mac[ETH_ALEN];
Expand Down Expand Up @@ -165,6 +184,9 @@ struct prestera_switch {
u32 mtu_min;
u32 mtu_max;
u8 id;
struct prestera_lag *lags;
u8 lag_member_max;
u8 lag_max;
};

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

bool prestera_netdev_check(const struct net_device *dev);

bool prestera_port_is_lag_member(const struct prestera_port *port);

struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);

u16 prestera_port_lag_id(const struct prestera_port *port);

#endif /* _PRESTERA_H_ */
180 changes: 168 additions & 12 deletions drivers/net/ethernet/marvell/prestera/prestera_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ enum prestera_cmd_type_t {
PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
PRESTERA_CMD_TYPE_RXTX_PORT_INIT = 0x801,

PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901,
PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902,
PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903,

PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,

PRESTERA_CMD_TYPE_ACK = 0x10000,
Expand Down Expand Up @@ -133,6 +138,12 @@ enum {
PRESTERA_FC_SYMM_ASYMM,
};

enum {
PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,
PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,
PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,
};

struct prestera_fw_event_handler {
struct list_head list;
struct rcu_head rcu;
Expand Down Expand Up @@ -174,6 +185,8 @@ struct prestera_msg_switch_init_resp {
u32 port_count;
u32 mtu_max;
u8 switch_id;
u8 lag_max;
u8 lag_member_max;
};

struct prestera_msg_port_autoneg_param {
Expand Down Expand Up @@ -261,8 +274,13 @@ struct prestera_msg_vlan_req {
struct prestera_msg_fdb_req {
struct prestera_msg_cmd cmd;
u8 dest_type;
u32 port;
u32 dev;
union {
struct {
u32 port;
u32 dev;
};
u16 lag_id;
} dest;
u8 mac[ETH_ALEN];
u16 vid;
u8 dynamic;
Expand Down Expand Up @@ -305,6 +323,13 @@ struct prestera_msg_rxtx_port_req {
u32 dev;
};

struct prestera_msg_lag_req {
struct prestera_msg_cmd cmd;
u32 port;
u32 dev;
u16 lag_id;
};

struct prestera_msg_event {
u16 type;
u16 id;
Expand All @@ -327,7 +352,10 @@ union prestera_msg_event_fdb_param {
struct prestera_msg_event_fdb {
struct prestera_msg_event id;
u8 dest_type;
u32 port_id;
union {
u32 port_id;
u16 lag_id;
} dest;
u32 vid;
union prestera_msg_event_fdb_param param;
};
Expand Down Expand Up @@ -398,7 +426,19 @@ static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt)
{
struct prestera_msg_event_fdb *hw_evt = msg;

evt->fdb_evt.port_id = hw_evt->port_id;
switch (hw_evt->dest_type) {
case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT:
evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT;
evt->fdb_evt.dest.port_id = hw_evt->dest.port_id;
break;
case PRESTERA_HW_FDB_ENTRY_TYPE_LAG:
evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG;
evt->fdb_evt.dest.lag_id = hw_evt->dest.lag_id;
break;
default:
return -EINVAL;
}

evt->fdb_evt.vid = hw_evt->vid;

ether_addr_copy(evt->fdb_evt.data.mac, hw_evt->param.mac);
Expand Down Expand Up @@ -543,6 +583,8 @@ int prestera_hw_switch_init(struct prestera_switch *sw)
sw->mtu_min = PRESTERA_MIN_MTU;
sw->mtu_max = resp.mtu_max;
sw->id = resp.switch_id;
sw->lag_member_max = resp.lag_member_max;
sw->lag_max = resp.lag_max;

return 0;
}
Expand Down Expand Up @@ -1150,8 +1192,10 @@ int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac,
u16 vid, bool dynamic)
{
struct prestera_msg_fdb_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.dest = {
.dev = port->dev_id,
.port = port->hw_id,
},
.vid = vid,
.dynamic = dynamic,
};
Expand All @@ -1166,8 +1210,10 @@ int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
u16 vid)
{
struct prestera_msg_fdb_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.dest = {
.dev = port->dev_id,
.port = port->hw_id,
},
.vid = vid,
};

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

int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
const unsigned char *mac, u16 vid, bool dynamic)
{
struct prestera_msg_fdb_req req = {
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
.dest = {
.lag_id = lag_id,
},
.vid = vid,
.dynamic = dynamic,
};

ether_addr_copy(req.mac, mac);

return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_ADD,
&req.cmd, sizeof(req));
}

int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
const unsigned char *mac, u16 vid)
{
struct prestera_msg_fdb_req req = {
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
.dest = {
.lag_id = lag_id,
},
.vid = vid,
};

ether_addr_copy(req.mac, mac);

return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_DELETE,
&req.cmd, sizeof(req));
}

int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode)
{
struct prestera_msg_fdb_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.dest = {
.dev = port->dev_id,
.port = port->hw_id,
},
.flush_mode = mode,
};

Expand All @@ -1204,8 +1287,10 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
u32 mode)
{
struct prestera_msg_fdb_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.dest = {
.dev = port->dev_id,
.port = port->hw_id,
},
.vid = vid,
.flush_mode = mode,
};
Expand All @@ -1214,6 +1299,37 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
&req.cmd, sizeof(req));
}

int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
u32 mode)
{
struct prestera_msg_fdb_req req = {
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
.dest = {
.lag_id = lag_id,
},
.flush_mode = mode,
};

return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,
&req.cmd, sizeof(req));
}

int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
u16 lag_id, u16 vid, u32 mode)
{
struct prestera_msg_fdb_req req = {
.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
.dest = {
.lag_id = lag_id,
},
.vid = vid,
.flush_mode = mode,
};

return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,
&req.cmd, sizeof(req));
}

int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id)
{
struct prestera_msg_bridge_resp resp;
Expand Down Expand Up @@ -1295,6 +1411,46 @@ int prestera_hw_rxtx_port_init(struct prestera_port *port)
&req.cmd, sizeof(req));
}

int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id)
{
struct prestera_msg_lag_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.lag_id = lag_id,
};

return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_ADD,
&req.cmd, sizeof(req));
}

int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id)
{
struct prestera_msg_lag_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.lag_id = lag_id,
};

return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE,
&req.cmd, sizeof(req));
}

int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
bool enable)
{
struct prestera_msg_lag_req req = {
.port = port->hw_id,
.dev = port->dev_id,
.lag_id = lag_id,
};
u32 cmd;

cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE :
PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE;

return prestera_cmd(port->sw, cmd, &req.cmd, sizeof(req));
}

int prestera_hw_event_handler_register(struct prestera_switch *sw,
enum prestera_event_type type,
prestera_event_cb_t fn,
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/ethernet/marvell/prestera/prestera_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,18 @@ int prestera_hw_rxtx_init(struct prestera_switch *sw,
struct prestera_rxtx_params *params);
int prestera_hw_rxtx_port_init(struct prestera_port *port);

/* LAG API */
int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id);
int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id);
int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
bool enable);
int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
const unsigned char *mac, u16 vid, bool dynamic);
int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
const unsigned char *mac, u16 vid);
int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
u32 mode);
int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
u16 lag_id, u16 vid, u32 mode);

#endif /* _PRESTERA_HW_H_ */
Loading

0 comments on commit 255213c

Please sign in to comment.