net: marvell: prestera: define and implement MDB / flood domain API for entries creat...
authorOleksandr Mazur <oleksandr.mazur@plvision.eu>
Mon, 11 Jul 2022 11:28:21 +0000 (14:28 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Jul 2022 11:14:05 +0000 (12:14 +0100)
Define and implement prestera API calls for managing MDB and
  flood domain (ports) entries (create / delete / find calls).

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>
drivers/net/ethernet/marvell/prestera/prestera.h
drivers/net/ethernet/marvell/prestera/prestera_main.c

index bf7ecb1..f22fab0 100644 (file)
@@ -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_ */
index 4b95ef3..04abff9 100644 (file)
@@ -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;