[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250622093756.2895000-9-lukma@denx.de>
Date: Sun, 22 Jun 2025 11:37:53 +0200
From: Lukasz Majewski <lukma@...x.de>
To: Andrew Lunn <andrew+netdev@...n.ch>,
davem@...emloft.net,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Shawn Guo <shawnguo@...nel.org>
Cc: Sascha Hauer <s.hauer@...gutronix.de>,
Pengutronix Kernel Team <kernel@...gutronix.de>,
Fabio Estevam <festevam@...il.com>,
Richard Cochran <richardcochran@...il.com>,
netdev@...r.kernel.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
imx@...ts.linux.dev,
linux-arm-kernel@...ts.infradead.org,
Stefan Wahren <wahrenst@....net>,
Simon Horman <horms@...nel.org>,
Lukasz Majewski <lukma@...x.de>
Subject: [net-next v13 08/11] net: mtip: Extend the L2 switch driver for imx287 with bridge operations
After this change the MTIP L2 switch can be configured as offloading
device for packet switching when bridge on their interfaces is created.
Signed-off-by: Lukasz Majewski <lukma@...x.de>
---
Changes for v13:
- New patch - created by excluding some code from large (i.e. v12 and
earlier) MTIP driver
---
.../net/ethernet/freescale/mtipsw/Makefile | 2 +-
.../net/ethernet/freescale/mtipsw/mtipl2sw.c | 6 +
.../net/ethernet/freescale/mtipsw/mtipl2sw.h | 2 +
.../ethernet/freescale/mtipsw/mtipl2sw_br.c | 120 ++++++++++++++++++
4 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw_br.c
diff --git a/drivers/net/ethernet/freescale/mtipsw/Makefile b/drivers/net/ethernet/freescale/mtipsw/Makefile
index a99aaf6ddfb2..81e2b0e03e6c 100644
--- a/drivers/net/ethernet/freescale/mtipsw/Makefile
+++ b/drivers/net/ethernet/freescale/mtipsw/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_FEC_MTIP_L2SW) += nxp-mtipl2sw.o
-nxp-mtipl2sw-objs := mtipl2sw.o mtipl2sw_mgnt.o
+nxp-mtipl2sw-objs := mtipl2sw.o mtipl2sw_mgnt.o mtipl2sw_br.o
diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
index 36700951cc97..95a2b874fd9c 100644
--- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
+++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
@@ -1918,6 +1918,10 @@ static int mtip_sw_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(&pdev->dev, ret, "Could not alloc IRQ\n");
+ ret = mtip_register_notifiers(fep);
+ if (ret)
+ return ret;
+
ret = mtip_ndev_init(fep, pdev);
if (ret) {
dev_err(&pdev->dev, "%s: Failed to create virtual ndev (%d)\n",
@@ -1959,6 +1963,7 @@ static int mtip_sw_probe(struct platform_device *pdev)
dma_init_err:
mtip_ndev_cleanup(fep);
ndev_init_err:
+ mtip_unregister_notifiers(fep);
return ret;
}
@@ -1967,6 +1972,7 @@ static void mtip_sw_remove(struct platform_device *pdev)
{
struct switch_enet_private *fep = platform_get_drvdata(pdev);
+ mtip_unregister_notifiers(fep);
mtip_ndev_cleanup(fep);
mtip_mii_remove(fep);
diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h
index 458c06f5be68..e85034df7031 100644
--- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h
+++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h
@@ -647,6 +647,8 @@ int mtip_port_learning_config(struct switch_enet_private *fep, int port,
int mtip_port_blocking_config(struct switch_enet_private *fep, int port,
bool enable);
bool mtip_is_switch_netdev_port(const struct net_device *ndev);
+int mtip_register_notifiers(struct switch_enet_private *fep);
+void mtip_unregister_notifiers(struct switch_enet_private *fep);
int mtip_port_enable_config(struct switch_enet_private *fep, int port,
bool tx_en, bool rx_en);
void mtip_clear_atable(struct switch_enet_private *fep);
diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_br.c b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_br.c
new file mode 100644
index 000000000000..edfd95a7790d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_br.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * L2 switch Controller driver for MTIP block - bridge network interface
+ *
+ * Copyright (C) 2025 DENX Software Engineering GmbH
+ * Lukasz Majewski <lukma@...x.de>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#include "mtipl2sw.h"
+
+static int mtip_ndev_port_link(struct net_device *ndev,
+ struct net_device *br_ndev,
+ struct netlink_ext_ack *extack)
+{
+ struct mtip_ndev_priv *priv = netdev_priv(ndev), *other_priv;
+ struct switch_enet_private *fep = priv->fep;
+ struct net_device *other_ndev;
+
+ /* Check if one port of MTIP switch is already bridged */
+ if (fep->br_members && !fep->br_offload) {
+ /* Get the second bridge ndev */
+ other_ndev = fep->ndev[fep->br_members - 1];
+ other_priv = netdev_priv(other_ndev);
+ if (other_priv->master_dev != br_ndev) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "L2 offloading only possible for the same bridge!");
+ return notifier_from_errno(-EOPNOTSUPP);
+ }
+
+ fep->br_offload = 1;
+ mtip_switch_dis_port_separation(fep);
+ mtip_clear_atable(fep);
+ }
+
+ if (!priv->master_dev)
+ priv->master_dev = br_ndev;
+
+ fep->br_members |= BIT(priv->portnum - 1);
+
+ dev_dbg(&ndev->dev,
+ "%s: ndev: %s br: %s fep: %p members: 0x%x offload: %d\n",
+ __func__, ndev->name, br_ndev->name, fep, fep->br_members,
+ fep->br_offload);
+
+ return NOTIFY_DONE;
+}
+
+static void mtip_netdevice_port_unlink(struct net_device *ndev)
+{
+ struct mtip_ndev_priv *priv = netdev_priv(ndev);
+ struct switch_enet_private *fep = priv->fep;
+
+ dev_dbg(&ndev->dev, "%s: ndev: %s members: 0x%x\n", __func__,
+ ndev->name, fep->br_members);
+
+ fep->br_members &= ~BIT(priv->portnum - 1);
+ priv->master_dev = NULL;
+
+ if (fep->br_members && fep->br_offload) {
+ fep->br_offload = 0;
+ mtip_switch_en_port_separation(fep);
+ mtip_clear_atable(fep);
+ }
+}
+
+/* netdev notifier */
+static int mtip_netdevice_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct netlink_ext_ack *extack;
+ int ret = NOTIFY_DONE;
+
+ if (!mtip_is_switch_netdev_port(ndev))
+ return NOTIFY_DONE;
+
+ extack = netdev_notifier_info_to_extack(&info->info);
+
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ if (!netif_is_bridge_master(info->upper_dev))
+ break;
+
+ if (info->linking)
+ ret = mtip_ndev_port_link(ndev, info->upper_dev,
+ extack);
+ else
+ mtip_netdevice_port_unlink(ndev);
+
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return notifier_from_errno(ret);
+}
+
+static struct notifier_block mtip_netdevice_nb __read_mostly = {
+ .notifier_call = mtip_netdevice_event,
+};
+
+int mtip_register_notifiers(struct switch_enet_private *fep)
+{
+ int ret = register_netdevice_notifier(&mtip_netdevice_nb);
+
+ if (ret)
+ dev_err(&fep->pdev->dev, "can't register netdevice notifier\n");
+
+ return ret;
+}
+
+void mtip_unregister_notifiers(struct switch_enet_private *fep)
+{
+ unregister_netdevice_notifier(&mtip_netdevice_nb);
+}
--
2.39.5
Powered by blists - more mailing lists