Commit fec7c9c7 authored by Oleksandr Mazur's avatar Oleksandr Mazur Committed by David S. Miller

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: default avatarYevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: default avatarYevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: default avatarOleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 116f5af7
......@@ -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)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment