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

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
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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);

+202 −0
Original line number Diff line number Diff line
@@ -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));
}
+11 −0
Original line number Diff line number Diff line
@@ -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_ */
+24 −0
Original line number Diff line number Diff line
@@ -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)
{