net: marvell: prestera: define MDB/flood domain entries and HW API to offload them to the HW
Define MDB entry that can be offloaded:
- FDB entry, that defines an multicast group to which traffic can be
replicated to;
Define flood domain:
- Arrangement of ports (list), that have joined multicast group, which
would receive and replicate to multicast traffic of specified group;
Define flood domain port:
- single flood domain list entry, that is associated with any given
bridge port interface (could be LAG interface or physical port-member).
Applicable to both Q and D bridges;
Co-developed-by: Yevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: Yevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
116f5af7c3
commit
fec7c9c73f
@@ -20,6 +20,26 @@ struct prestera_fw_rev {
|
||||
u16 sub;
|
||||
};
|
||||
|
||||
struct prestera_flood_domain {
|
||||
struct prestera_switch *sw;
|
||||
struct list_head flood_domain_port_list;
|
||||
u32 idx;
|
||||
};
|
||||
|
||||
struct prestera_mdb_entry {
|
||||
struct prestera_switch *sw;
|
||||
struct prestera_flood_domain *flood_domain;
|
||||
unsigned char addr[ETH_ALEN];
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
struct prestera_flood_domain_port {
|
||||
struct prestera_flood_domain *flood_domain;
|
||||
struct net_device *dev;
|
||||
struct list_head flood_domain_port_node;
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
struct prestera_port_stats {
|
||||
u64 good_octets_received;
|
||||
u64 bad_octets_received;
|
||||
@@ -342,6 +362,8 @@ bool prestera_netdev_check(const struct net_device *dev);
|
||||
int prestera_is_valid_mac_addr(struct prestera_port *port, const u8 *addr);
|
||||
|
||||
bool prestera_port_is_lag_member(const struct prestera_port *port);
|
||||
int prestera_lag_id(struct prestera_switch *sw,
|
||||
struct net_device *lag_dev, u16 *lag_id);
|
||||
|
||||
struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);
|
||||
|
||||
|
||||
@@ -60,6 +60,14 @@ enum prestera_cmd_type_t {
|
||||
PRESTERA_CMD_TYPE_ROUTER_VR_CREATE = 0x630,
|
||||
PRESTERA_CMD_TYPE_ROUTER_VR_DELETE = 0x631,
|
||||
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE = 0x700,
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY = 0x701,
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET = 0x702,
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET = 0x703,
|
||||
|
||||
PRESTERA_CMD_TYPE_MDB_CREATE = 0x704,
|
||||
PRESTERA_CMD_TYPE_MDB_DESTROY = 0x705,
|
||||
|
||||
PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
|
||||
|
||||
PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
|
||||
@@ -185,6 +193,12 @@ struct prestera_fw_event_handler {
|
||||
void *arg;
|
||||
};
|
||||
|
||||
enum {
|
||||
PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_REG_PORT = 0,
|
||||
PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG = 1,
|
||||
PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_MAX = 2,
|
||||
};
|
||||
|
||||
struct prestera_msg_cmd {
|
||||
__le32 type;
|
||||
};
|
||||
@@ -627,6 +641,57 @@ struct prestera_msg_event_fdb {
|
||||
u8 dest_type;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_create_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_create_resp {
|
||||
struct prestera_msg_ret ret;
|
||||
__le32 flood_domain_idx;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_destroy_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
__le32 flood_domain_idx;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_ports_set_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
__le32 flood_domain_idx;
|
||||
__le32 ports_num;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_ports_reset_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
__le32 flood_domain_idx;
|
||||
};
|
||||
|
||||
struct prestera_msg_flood_domain_port {
|
||||
union {
|
||||
struct {
|
||||
__le32 port_num;
|
||||
__le32 dev_num;
|
||||
};
|
||||
__le16 lag_id;
|
||||
};
|
||||
__le16 vid;
|
||||
__le16 port_type;
|
||||
};
|
||||
|
||||
struct prestera_msg_mdb_create_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
__le32 flood_domain_idx;
|
||||
__le16 vid;
|
||||
u8 mac[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct prestera_msg_mdb_destroy_req {
|
||||
struct prestera_msg_cmd cmd;
|
||||
__le32 flood_domain_idx;
|
||||
__le16 vid;
|
||||
u8 mac[ETH_ALEN];
|
||||
};
|
||||
|
||||
static void prestera_hw_build_tests(void)
|
||||
{
|
||||
/* check requests */
|
||||
@@ -654,10 +719,17 @@ static void prestera_hw_build_tests(void)
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_vr_req) != 8);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_lpm_req) != 36);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_policer_req) != 36);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_create_req) != 4);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_destroy_req) != 8);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_set_req) != 12);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_reset_req) != 8);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_create_req) != 16);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_destroy_req) != 16);
|
||||
|
||||
/* structure that are part of req/resp fw messages */
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_iface) != 16);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_ip_addr) != 20);
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_port) != 12);
|
||||
|
||||
/* check responses */
|
||||
BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8);
|
||||
@@ -2194,3 +2266,133 @@ int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw,
|
||||
return prestera_cmd(sw, PRESTERA_CMD_TYPE_POLICER_SET,
|
||||
&req.cmd, sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_flood_domain_create(struct prestera_flood_domain *domain)
|
||||
{
|
||||
struct prestera_msg_flood_domain_create_resp resp;
|
||||
struct prestera_msg_flood_domain_create_req req;
|
||||
int err;
|
||||
|
||||
err = prestera_cmd_ret(domain->sw,
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE, &req.cmd,
|
||||
sizeof(req), &resp.ret, sizeof(resp));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
domain->idx = __le32_to_cpu(resp.flood_domain_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prestera_hw_flood_domain_destroy(struct prestera_flood_domain *domain)
|
||||
{
|
||||
struct prestera_msg_flood_domain_destroy_req req = {
|
||||
.flood_domain_idx = __cpu_to_le32(domain->idx),
|
||||
};
|
||||
|
||||
return prestera_cmd(domain->sw, PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY,
|
||||
&req.cmd, sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_flood_domain_ports_set(struct prestera_flood_domain *domain)
|
||||
{
|
||||
struct prestera_flood_domain_port *flood_domain_port;
|
||||
struct prestera_msg_flood_domain_ports_set_req *req;
|
||||
struct prestera_msg_flood_domain_port *ports;
|
||||
struct prestera_switch *sw = domain->sw;
|
||||
struct prestera_port *port;
|
||||
u32 ports_num = 0;
|
||||
int buf_size;
|
||||
void *buff;
|
||||
u16 lag_id;
|
||||
int err;
|
||||
|
||||
list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list,
|
||||
flood_domain_port_node)
|
||||
ports_num++;
|
||||
|
||||
if (!ports_num)
|
||||
return -EINVAL;
|
||||
|
||||
buf_size = sizeof(*req) + sizeof(*ports) * ports_num;
|
||||
|
||||
buff = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!buff)
|
||||
return -ENOMEM;
|
||||
|
||||
req = buff;
|
||||
ports = buff + sizeof(*req);
|
||||
|
||||
req->flood_domain_idx = __cpu_to_le32(domain->idx);
|
||||
req->ports_num = __cpu_to_le32(ports_num);
|
||||
|
||||
list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list,
|
||||
flood_domain_port_node) {
|
||||
if (netif_is_lag_master(flood_domain_port->dev)) {
|
||||
if (prestera_lag_id(sw, flood_domain_port->dev,
|
||||
&lag_id)) {
|
||||
kfree(buff);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ports->port_type =
|
||||
__cpu_to_le16(PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG);
|
||||
ports->lag_id = __cpu_to_le16(lag_id);
|
||||
} else {
|
||||
port = prestera_port_dev_lower_find(flood_domain_port->dev);
|
||||
|
||||
ports->port_type =
|
||||
__cpu_to_le16(PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT);
|
||||
ports->dev_num = __cpu_to_le32(port->dev_id);
|
||||
ports->port_num = __cpu_to_le32(port->hw_id);
|
||||
}
|
||||
|
||||
ports->vid = __cpu_to_le16(flood_domain_port->vid);
|
||||
|
||||
ports++;
|
||||
}
|
||||
|
||||
err = prestera_cmd(sw, PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET,
|
||||
&req->cmd, buf_size);
|
||||
|
||||
kfree(buff);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int prestera_hw_flood_domain_ports_reset(struct prestera_flood_domain *domain)
|
||||
{
|
||||
struct prestera_msg_flood_domain_ports_reset_req req = {
|
||||
.flood_domain_idx = __cpu_to_le32(domain->idx),
|
||||
};
|
||||
|
||||
return prestera_cmd(domain->sw,
|
||||
PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET, &req.cmd,
|
||||
sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_mdb_create(struct prestera_mdb_entry *mdb)
|
||||
{
|
||||
struct prestera_msg_mdb_create_req req = {
|
||||
.flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx),
|
||||
.vid = __cpu_to_le16(mdb->vid),
|
||||
};
|
||||
|
||||
memcpy(req.mac, mdb->addr, ETH_ALEN);
|
||||
|
||||
return prestera_cmd(mdb->sw, PRESTERA_CMD_TYPE_MDB_CREATE, &req.cmd,
|
||||
sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_mdb_destroy(struct prestera_mdb_entry *mdb)
|
||||
{
|
||||
struct prestera_msg_mdb_destroy_req req = {
|
||||
.flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx),
|
||||
.vid = __cpu_to_le16(mdb->vid),
|
||||
};
|
||||
|
||||
memcpy(req.mac, mdb->addr, ETH_ALEN);
|
||||
|
||||
return prestera_cmd(mdb->sw, PRESTERA_CMD_TYPE_MDB_DESTROY, &req.cmd,
|
||||
sizeof(req));
|
||||
}
|
||||
|
||||
@@ -144,6 +144,8 @@ struct prestera_acl_hw_action_info;
|
||||
struct prestera_acl_iface;
|
||||
struct prestera_counter_stats;
|
||||
struct prestera_iface;
|
||||
struct prestera_flood_domain;
|
||||
struct prestera_mdb_entry;
|
||||
|
||||
/* Switch API */
|
||||
int prestera_hw_switch_init(struct prestera_switch *sw);
|
||||
@@ -302,4 +304,13 @@ int prestera_hw_policer_release(struct prestera_switch *sw,
|
||||
int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw,
|
||||
u32 policer_id, u64 cir, u32 cbs);
|
||||
|
||||
/* Flood domain / MDB API */
|
||||
int prestera_hw_flood_domain_create(struct prestera_flood_domain *domain);
|
||||
int prestera_hw_flood_domain_destroy(struct prestera_flood_domain *domain);
|
||||
int prestera_hw_flood_domain_ports_set(struct prestera_flood_domain *domain);
|
||||
int prestera_hw_flood_domain_ports_reset(struct prestera_flood_domain *domain);
|
||||
|
||||
int prestera_hw_mdb_create(struct prestera_mdb_entry *mdb);
|
||||
int prestera_hw_mdb_destroy(struct prestera_mdb_entry *mdb);
|
||||
|
||||
#endif /* _PRESTERA_HW_H_ */
|
||||
|
||||
@@ -600,6 +600,30 @@ static struct prestera_lag *prestera_lag_by_dev(struct prestera_switch *sw,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int prestera_lag_id(struct prestera_switch *sw,
|
||||
struct net_device *lag_dev, u16 *lag_id)
|
||||
{
|
||||
struct prestera_lag *lag;
|
||||
int free_id = -1;
|
||||
int id;
|
||||
|
||||
for (id = 0; id < sw->lag_max; id++) {
|
||||
lag = prestera_lag_by_id(sw, id);
|
||||
if (lag->member_count) {
|
||||
if (lag->dev == lag_dev) {
|
||||
*lag_id = id;
|
||||
return 0;
|
||||
}
|
||||
} else if (free_id < 0) {
|
||||
free_id = id;
|
||||
}
|
||||
}
|
||||
if (free_id < 0)
|
||||
return -ENOSPC;
|
||||
*lag_id = free_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct prestera_lag *prestera_lag_create(struct prestera_switch *sw,
|
||||
struct net_device *lag_dev)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user