summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/marvell/prestera/prestera_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/marvell/prestera/prestera_main.c')
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_main.c110
1 files changed, 107 insertions, 3 deletions
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index bb51ee5646cd..9bd57b89d1d0 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -14,6 +14,7 @@
#include "prestera_rxtx.h"
#include "prestera_devlink.h"
#include "prestera_ethtool.h"
+#include "prestera_switchdev.h"
#define PRESTERA_MTU_DEFAULT 1536
@@ -23,6 +24,29 @@
static struct workqueue_struct *prestera_wq;
+int prestera_port_pvid_set(struct prestera_port *port, u16 vid)
+{
+ enum prestera_accept_frm_type frm_type;
+ int err;
+
+ frm_type = PRESTERA_ACCEPT_FRAME_TYPE_TAGGED;
+
+ if (vid) {
+ err = prestera_hw_vlan_port_vid_set(port, vid);
+ if (err)
+ return err;
+
+ frm_type = PRESTERA_ACCEPT_FRAME_TYPE_ALL;
+ }
+
+ err = prestera_hw_port_accept_frm_type(port, frm_type);
+ if (err && frm_type == PRESTERA_ACCEPT_FRAME_TYPE_ALL)
+ prestera_hw_vlan_port_vid_set(port, port->pvid);
+
+ port->pvid = vid;
+ return 0;
+}
+
struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
u32 dev_id, u32 hw_id)
{
@@ -38,8 +62,7 @@ struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
return port;
}
-static struct prestera_port *prestera_find_port(struct prestera_switch *sw,
- u32 id)
+struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id)
{
struct prestera_port *port = NULL;
@@ -261,6 +284,8 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
port = netdev_priv(dev);
+ INIT_LIST_HEAD(&port->vlans_list);
+ port->pvid = PRESTERA_DEFAULT_VID;
port->dev = dev;
port->id = id;
port->sw = sw;
@@ -452,6 +477,71 @@ static int prestera_switch_set_base_mac_addr(struct prestera_switch *sw)
return prestera_hw_switch_mac_set(sw, sw->base_mac);
}
+bool prestera_netdev_check(const struct net_device *dev)
+{
+ return dev->netdev_ops == &prestera_netdev_ops;
+}
+
+static int prestera_lower_dev_walk(struct net_device *dev, void *data)
+{
+ struct prestera_port **pport = data;
+
+ if (prestera_netdev_check(dev)) {
+ *pport = netdev_priv(dev);
+ return 1;
+ }
+
+ return 0;
+}
+
+struct prestera_port *prestera_port_dev_lower_find(struct net_device *dev)
+{
+ struct prestera_port *port = NULL;
+
+ if (prestera_netdev_check(dev))
+ return netdev_priv(dev);
+
+ netdev_walk_all_lower_dev(dev, prestera_lower_dev_walk, &port);
+
+ return port;
+}
+
+static int prestera_netdev_port_event(struct net_device *dev,
+ unsigned long event, void *ptr)
+{
+ switch (event) {
+ case NETDEV_PRECHANGEUPPER:
+ case NETDEV_CHANGEUPPER:
+ return prestera_bridge_port_event(dev, event, ptr);
+ default:
+ return 0;
+ }
+}
+
+static int prestera_netdev_event_handler(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ int err = 0;
+
+ if (prestera_netdev_check(dev))
+ err = prestera_netdev_port_event(dev, event, ptr);
+
+ return notifier_from_errno(err);
+}
+
+static int prestera_netdev_event_handler_register(struct prestera_switch *sw)
+{
+ sw->netdev_nb.notifier_call = prestera_netdev_event_handler;
+
+ return register_netdevice_notifier(&sw->netdev_nb);
+}
+
+static void prestera_netdev_event_handler_unregister(struct prestera_switch *sw)
+{
+ unregister_netdevice_notifier(&sw->netdev_nb);
+}
+
static int prestera_switch_init(struct prestera_switch *sw)
{
int err;
@@ -469,10 +559,18 @@ static int prestera_switch_init(struct prestera_switch *sw)
if (err)
return err;
- err = prestera_rxtx_switch_init(sw);
+ err = prestera_netdev_event_handler_register(sw);
if (err)
return err;
+ err = prestera_switchdev_init(sw);
+ if (err)
+ goto err_swdev_register;
+
+ err = prestera_rxtx_switch_init(sw);
+ if (err)
+ goto err_rxtx_register;
+
err = prestera_event_handlers_register(sw);
if (err)
goto err_handlers_register;
@@ -493,6 +591,10 @@ err_dl_register:
prestera_event_handlers_unregister(sw);
err_handlers_register:
prestera_rxtx_switch_fini(sw);
+err_rxtx_register:
+ prestera_switchdev_fini(sw);
+err_swdev_register:
+ prestera_netdev_event_handler_unregister(sw);
prestera_hw_switch_fini(sw);
return err;
@@ -504,6 +606,8 @@ static void prestera_switch_fini(struct prestera_switch *sw)
prestera_devlink_unregister(sw);
prestera_event_handlers_unregister(sw);
prestera_rxtx_switch_fini(sw);
+ prestera_switchdev_fini(sw);
+ prestera_netdev_event_handler_unregister(sw);
prestera_hw_switch_fini(sw);
}