From nobody Mon Oct 6 22:53:59 2025 Received: from mx.denx.de (mx.denx.de [89.58.32.78]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2C17D2EE61F; Wed, 16 Jul 2025 21:48:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.58.32.78 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752702501; cv=none; b=DTdCRCM1n2Phgj2iU95a3c8yfMZlIuE2pTFhVmyF7h+8rmnSkjRK7ZALrun2VGxwvoiuQxW4ZUVkzHrYmbsP2cwwjApuSltPEa6KMVVrmLTm3PRXuRjoBWQto2sbGCI/z17efw0FizfpU8orHi6cLAbdchDQedcOLn/FX0Jk01Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752702501; c=relaxed/simple; bh=1S2FQFcfi0E7csk+aBErSIRunRhlPa4iqQ9fX6QQeUI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=M32rdG2zp5XODgvLKO7POPchVfzGUdROuqELfOj/txhuspTvFHI5fhAs7N4GmfXlMu+CmyctffXnfQAvDhO/K5+iu9aO2oYqx50ertvU6nFvNxIS/e1PrjkM14KZXN9qyJngBIIrNxSbkKu6dqyyjRlvWE0JWP4cezo/Q8jKpX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=denx.de; spf=pass smtp.mailfrom=denx.de; dkim=pass (2048-bit key) header.d=denx.de header.i=@denx.de header.b=Ziq+bHue; arc=none smtp.client-ip=89.58.32.78 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=denx.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=denx.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=denx.de header.i=@denx.de header.b="Ziq+bHue" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 68FC010272378; Wed, 16 Jul 2025 23:48:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=mx-20241105; t=1752702497; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=6BNzi9pF6pKSeNX9iple8zeYVhieZk3Cx6DiJRZiQRU=; b=Ziq+bHueghFNT0SFeHvzKPCtZ3wptySDz8k08jCtqrt59/6Cv5ITKlxfuQj9NimpO+vhTV okV9ZIC41vCPOhF2y82wOXBZE1DP94p3n4FsPalnUskHiRMyzlZUKgTcstVrYEJZQr7FRR OEYKnmss4LOgTDRwdNJrxkgWJYVtfv7DCqJ3ITPiRvuXP+6IpZf8fvRsxPeC0bhQ1dRfUF 5VzhHmMmMMu8IwOR91JmcZvIA3xJgzJ9VxhY5bkJkLQG5QGgHwFeC6EL1T/XpXWnAz8iAB PUDp/fDsZF1d4DR0IonG1SDok5ViAJv5PIOKHC6GuLkCHMkCfKUZI/YoZ3v2qQ== From: Lukasz Majewski To: Andrew Lunn , davem@davemloft.net, Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Shawn Guo Cc: Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , Richard Cochran , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Stefan Wahren , Simon Horman , Lukasz Majewski Subject: [net-next v15 09/12] net: mtip: Extend the L2 switch driver for imx287 with bridge operations Date: Wed, 16 Jul 2025 23:47:28 +0200 Message-Id: <20250716214731.3384273-10-lukma@denx.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250716214731.3384273-1-lukma@denx.de> References: <20250716214731.3384273-1-lukma@denx.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" 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 --- Changes for v13: - New patch - created by excluding some code from large (i.e. v12 and earlier) MTIP driver Changes for v14: - None Changes for v15: - None --- .../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/e= thernet/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 =20 obj-$(CONFIG_FEC_MTIP_L2SW) +=3D nxp-mtipl2sw.o -nxp-mtipl2sw-objs :=3D mtipl2sw.o mtipl2sw_mgnt.o +nxp-mtipl2sw-objs :=3D 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 05e7fcba5c48..a0bcd5e025b7 100644 --- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c @@ -1883,6 +1883,10 @@ static int mtip_sw_probe(struct platform_device *pde= v) if (ret) return dev_err_probe(&pdev->dev, ret, "Could not alloc IRQ\n"); =20 + ret =3D mtip_register_notifiers(fep); + if (ret) + return ret; + ret =3D mtip_ndev_init(fep, pdev); if (ret) { dev_err(&pdev->dev, "%s: Failed to create virtual ndev (%d)\n", @@ -1914,6 +1918,7 @@ static int mtip_sw_probe(struct platform_device *pdev) dma_init_err: mtip_ndev_cleanup(fep); ndev_init_err: + mtip_unregister_notifiers(fep); =20 return ret; } @@ -1922,6 +1927,7 @@ static void mtip_sw_remove(struct platform_device *pd= ev) { struct switch_enet_private *fep =3D platform_get_drvdata(pdev); =20 + mtip_unregister_notifiers(fep); mtip_ndev_cleanup(fep); =20 mtip_mii_remove(fep); diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h b/drivers/net= /ethernet/freescale/mtipsw/mtipl2sw.h index a8fb8c4e1351..a126f6b60d7f 100644 --- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h @@ -644,6 +644,8 @@ int mtip_port_learning_config(struct switch_enet_privat= e *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 + */ + +#include +#include +#include + +#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 =3D netdev_priv(ndev), *other_priv; + struct switch_enet_private *fep =3D 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 =3D fep->ndev[fep->br_members - 1]; + other_priv =3D netdev_priv(other_ndev); + if (other_priv->master_dev !=3D br_ndev) { + NL_SET_ERR_MSG_MOD(extack, + "L2 offloading only possible for the same bridge!"); + return notifier_from_errno(-EOPNOTSUPP); + } + + fep->br_offload =3D 1; + mtip_switch_dis_port_separation(fep); + mtip_clear_atable(fep); + } + + if (!priv->master_dev) + priv->master_dev =3D br_ndev; + + fep->br_members |=3D 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 =3D netdev_priv(ndev); + struct switch_enet_private *fep =3D priv->fep; + + dev_dbg(&ndev->dev, "%s: ndev: %s members: 0x%x\n", __func__, + ndev->name, fep->br_members); + + fep->br_members &=3D ~BIT(priv->portnum - 1); + priv->master_dev =3D NULL; + + if (fep->br_members && fep->br_offload) { + fep->br_offload =3D 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 =3D netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info =3D ptr; + struct netlink_ext_ack *extack; + int ret =3D NOTIFY_DONE; + + if (!mtip_is_switch_netdev_port(ndev)) + return NOTIFY_DONE; + + extack =3D 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 =3D 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 =3D { + .notifier_call =3D mtip_netdevice_event, +}; + +int mtip_register_notifiers(struct switch_enet_private *fep) +{ + int ret =3D 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); +} --=20 2.39.5