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

net: marvell: prestera: define and implement MDB / flood domain API for...


net: marvell: prestera: define and implement MDB / flood domain API for entries creation and deletion

Define and implement prestera API calls for managing MDB and
  flood domain (ports) entries (create / delete / find calls).

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 fec7c9c7
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -369,4 +369,23 @@ struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);

u16 prestera_port_lag_id(const struct prestera_port *port);

struct prestera_mdb_entry *
prestera_mdb_entry_create(struct prestera_switch *sw,
			  const unsigned char *addr, u16 vid);
void prestera_mdb_entry_destroy(struct prestera_mdb_entry *mdb_entry);

struct prestera_flood_domain *
prestera_flood_domain_create(struct prestera_switch *sw);
void prestera_flood_domain_destroy(struct prestera_flood_domain *flood_domain);

int
prestera_flood_domain_port_create(struct prestera_flood_domain *flood_domain,
				  struct net_device *dev,
				  u16 vid);
void
prestera_flood_domain_port_destroy(struct prestera_flood_domain_port *port);
struct prestera_flood_domain_port *
prestera_flood_domain_port_find(struct prestera_flood_domain *flood_domain,
				struct net_device *dev, u16 vid);

#endif /* _PRESTERA_H_ */
+144 −0
Original line number Diff line number Diff line
@@ -915,6 +915,150 @@ static int prestera_netdev_event_handler(struct notifier_block *nb,
	return notifier_from_errno(err);
}

struct prestera_mdb_entry *
prestera_mdb_entry_create(struct prestera_switch *sw,
			  const unsigned char *addr, u16 vid)
{
	struct prestera_flood_domain *flood_domain;
	struct prestera_mdb_entry *mdb_entry;

	mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
	if (!mdb_entry)
		goto err_mdb_alloc;

	flood_domain = prestera_flood_domain_create(sw);
	if (!flood_domain)
		goto err_flood_domain_create;

	mdb_entry->sw = sw;
	mdb_entry->vid = vid;
	mdb_entry->flood_domain = flood_domain;
	ether_addr_copy(mdb_entry->addr, addr);

	if (prestera_hw_mdb_create(mdb_entry))
		goto err_mdb_hw_create;

	return mdb_entry;

err_mdb_hw_create:
	prestera_flood_domain_destroy(flood_domain);
err_flood_domain_create:
	kfree(mdb_entry);
err_mdb_alloc:
	return NULL;
}

void prestera_mdb_entry_destroy(struct prestera_mdb_entry *mdb_entry)
{
	prestera_hw_mdb_destroy(mdb_entry);
	prestera_flood_domain_destroy(mdb_entry->flood_domain);
	kfree(mdb_entry);
}

struct prestera_flood_domain *
prestera_flood_domain_create(struct prestera_switch *sw)
{
	struct prestera_flood_domain *domain;

	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
	if (!domain)
		return NULL;

	domain->sw = sw;

	if (prestera_hw_flood_domain_create(domain)) {
		kfree(domain);
		return NULL;
	}

	INIT_LIST_HEAD(&domain->flood_domain_port_list);

	return domain;
}

void prestera_flood_domain_destroy(struct prestera_flood_domain *flood_domain)
{
	WARN_ON(!list_empty(&flood_domain->flood_domain_port_list));
	WARN_ON_ONCE(prestera_hw_flood_domain_destroy(flood_domain));
	kfree(flood_domain);
}

int
prestera_flood_domain_port_create(struct prestera_flood_domain *flood_domain,
				  struct net_device *dev,
				  u16 vid)
{
	struct prestera_flood_domain_port *flood_domain_port;
	bool is_first_port_in_list = false;
	int err;

	flood_domain_port = kzalloc(sizeof(*flood_domain_port), GFP_KERNEL);
	if (!flood_domain_port) {
		err = -ENOMEM;
		goto err_port_alloc;
	}

	flood_domain_port->vid = vid;

	if (list_empty(&flood_domain->flood_domain_port_list))
		is_first_port_in_list = true;

	list_add(&flood_domain_port->flood_domain_port_node,
		 &flood_domain->flood_domain_port_list);

	flood_domain_port->flood_domain = flood_domain;
	flood_domain_port->dev = dev;

	if (!is_first_port_in_list) {
		err = prestera_hw_flood_domain_ports_reset(flood_domain);
		if (err)
			goto err_prestera_mdb_port_create_hw;
	}

	err = prestera_hw_flood_domain_ports_set(flood_domain);
	if (err)
		goto err_prestera_mdb_port_create_hw;

	return 0;

err_prestera_mdb_port_create_hw:
	list_del(&flood_domain_port->flood_domain_port_node);
	kfree(flood_domain_port);
err_port_alloc:
	return err;
}

void
prestera_flood_domain_port_destroy(struct prestera_flood_domain_port *port)
{
	struct prestera_flood_domain *flood_domain = port->flood_domain;

	list_del(&port->flood_domain_port_node);

	WARN_ON_ONCE(prestera_hw_flood_domain_ports_reset(flood_domain));

	if (!list_empty(&flood_domain->flood_domain_port_list))
		WARN_ON_ONCE(prestera_hw_flood_domain_ports_set(flood_domain));

	kfree(port);
}

struct prestera_flood_domain_port *
prestera_flood_domain_port_find(struct prestera_flood_domain *flood_domain,
				struct net_device *dev, u16 vid)
{
	struct prestera_flood_domain_port *flood_domain_port;

	list_for_each_entry(flood_domain_port,
			    &flood_domain->flood_domain_port_list,
			    flood_domain_port_node)
		if (flood_domain_port->dev == dev &&
		    vid == flood_domain_port->vid)
			return flood_domain_port;

	return NULL;
}

static int prestera_netdev_event_handler_register(struct prestera_switch *sw)
{
	sw->netdev_nb.notifier_call = prestera_netdev_event_handler;