From nobody Tue Oct 7 22:58:39 2025 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8215D20E030; Fri, 4 Jul 2025 05:51:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608298; cv=none; b=dEq4GG9jKcD194030pQU4NHH175Wt3tRUqwObqy1Hg1mW8oFVUCZybIuOFVpfBJn6o2UCMp3ukLa5TGfAfg6Ev40kvrewaUIDcljCzfc9JtRTAvIxUa8bmKaT7icRhOV63GrXz3UlNWqLPPd/DT8eQB8Ov+9iPN4/Bv8IuNzOtI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608298; c=relaxed/simple; bh=l4w4ScuC6+kKDFL0zv62ICBhy98vqkkl4tddPQXmdeU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jD1FtaHoGJ3LaMvHSiBmNo5MtlOhd9+8vp37swAc7VXDcr2Iu7TWycodXbP59WuPvSiiTK4QF+HoYV6xiEL85BDIoF22NaXcJC6ZfNarpQI5vpt3bgQmk4jnCq2PCnFZnimNsbm+3KgD8sSR9uUVEJPkEC1TeaulST8nG3DGi+M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com; spf=pass smtp.mailfrom=renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=renesas.com X-CSE-ConnectionGUID: goUBGLARRFqd3Uz3HLRZsQ== X-CSE-MsgGUID: O1KvNXh+RrqlDZHwcRQ6Wg== Received: from unknown (HELO relmlir6.idc.renesas.com) ([10.200.68.152]) by relmlie6.idc.renesas.com with ESMTP; 04 Jul 2025 14:51:36 +0900 Received: from [127.0.1.1] (unknown [10.226.78.19]) by relmlir6.idc.renesas.com (Postfix) with ESMTP id ADE5F41566DC; Fri, 4 Jul 2025 14:51:32 +0900 (JST) From: Michael Dege Date: Fri, 04 Jul 2025 07:51:15 +0200 Subject: [PATCH 1/3] net: renesas: rswitch: rename rswitch.c to rswitch_main.c Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250704-add_l2_switching-v1-1-ff882aacb258@renesas.com> References: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> In-Reply-To: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> To: Yoshihiro Shimoda , =?utf-8?q?Niklas_S=C3=B6derlund?= , Paul Barker , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Michael Dege , Nikita Yushchenko X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1751608288; l=1175; i=michael.dege@renesas.com; s=20250523; h=from:subject:message-id; bh=l4w4ScuC6+kKDFL0zv62ICBhy98vqkkl4tddPQXmdeU=; b=W5ViUsfkGSWf7NJwK1bZE7IAO0ERStN6t/54VfNN6UbjCL0f87bkGKKCuOumy3rcRGRWba2DV oJypbMvmSvNDIO3j3ppU3AxZjlsAsuoTJzTGCMl+WBPvQyQumRNYuLf X-Developer-Key: i=michael.dege@renesas.com; a=ed25519; pk=+gYTlVQ3/MlOju88OuKnXA7MlapP4lYqJn1F81HZGSo= Adding new functionality to the driver. Therefore splitting into multiple c files to keep them manageable. New functionality will be added to separate files. Signed-off-by: Michael Dege Reviewed-by: Andrew Lunn Reviewed-by: Niklas S=C3=B6derlund --- drivers/net/ethernet/renesas/Makefile | 1 + drivers/net/ethernet/renesas/{rswitch.c =3D> rswitch_main.c} | 0 2 files changed, 1 insertion(+) diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/r= enesas/Makefile index f65fc76f8b4df8dd9f24af836b6dc0772965366f..6222298bb5582b7091cf8de76ac= b83ac7dd39c11 100644 --- a/drivers/net/ethernet/renesas/Makefile +++ b/drivers/net/ethernet/renesas/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SH_ETH) +=3D sh_eth.o ravb-objs :=3D ravb_main.o ravb_ptp.o obj-$(CONFIG_RAVB) +=3D ravb.o =20 +rswitch-objs :=3D rswitch_main.o obj-$(CONFIG_RENESAS_ETHER_SWITCH) +=3D rswitch.o =20 obj-$(CONFIG_RENESAS_GEN4_PTP) +=3D rcar_gen4_ptp.o diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/= renesas/rswitch_main.c similarity index 100% rename from drivers/net/ethernet/renesas/rswitch.c rename to drivers/net/ethernet/renesas/rswitch_main.c --=20 2.49.0 From nobody Tue Oct 7 22:58:39 2025 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6383A20D517; Fri, 4 Jul 2025 05:51:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608304; cv=none; b=H2HvCXlSfhb2EhLNhD4u/kkg4en+iArgZ8w5AL51R+cvrrN4h/9vLG2U1u+fb/yKOA6Dz1mD6QcvamQJ+5tEpfilhrrpzS3smApjSC0DopT77TyA23E8m3+SWJu50mtJjiNMUCtNYa3KWNxCiXc/GZA8hmLVR5GUwqR9fwpR2Ps= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608304; c=relaxed/simple; bh=ecVPBy85iyjBludaaQ6oaRo0YgKa74EXmBwbk3LGlMA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VYYhO4hjMB0utxlwfo4hR/XF6volnM46sQZNFQ6HoyxkuyXwrWUvQNTsbSuCtn58bh2G/O5Lyxc/XgN/KEn9MA/SjNkFUvVwv205nQAUX0iD0PmxBeorg7XLxY4onGQfTDen018zclymgUXRpTyOqf0hIVYTH+Bh+5XXamzkIcE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com; spf=pass smtp.mailfrom=renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=renesas.com X-CSE-ConnectionGUID: zTq/GJCURcqZ2iUSuFvGtg== X-CSE-MsgGUID: x0hBWQEWRUiGH/9NvdC6iQ== Received: from unknown (HELO relmlir6.idc.renesas.com) ([10.200.68.152]) by relmlie5.idc.renesas.com with ESMTP; 04 Jul 2025 14:51:40 +0900 Received: from [127.0.1.1] (unknown [10.226.78.19]) by relmlir6.idc.renesas.com (Postfix) with ESMTP id 82E6D4156C50; Fri, 4 Jul 2025 14:51:36 +0900 (JST) From: Michael Dege Date: Fri, 04 Jul 2025 07:51:16 +0200 Subject: [PATCH 2/3] net: renesas: rswitch: add offloading for L2 switching Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250704-add_l2_switching-v1-2-ff882aacb258@renesas.com> References: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> In-Reply-To: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> To: Yoshihiro Shimoda , =?utf-8?q?Niklas_S=C3=B6derlund?= , Paul Barker , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Michael Dege , Nikita Yushchenko X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1751608288; l=21682; i=michael.dege@renesas.com; s=20250523; h=from:subject:message-id; bh=ecVPBy85iyjBludaaQ6oaRo0YgKa74EXmBwbk3LGlMA=; b=HQNBdT4capAnpo8mjYRHdGqpA7R399n4/vWYwiPVBL3O8UIIeoDoJ1SVjw4LZG4fdEc6LPcSx 4BtbXFRV02+BQ3dmcQRM4yQE3m1G25w+VYsDMqXns5pJfFtYPvsmfcb X-Developer-Key: i=michael.dege@renesas.com; a=ed25519; pk=+gYTlVQ3/MlOju88OuKnXA7MlapP4lYqJn1F81HZGSo= This commit adds hardware offloading for L2 switching on R-Car S4 Signed-off-by: Michael Dege Signed-off-by: Nikita Yushchenko --- drivers/net/ethernet/renesas/Makefile | 2 +- drivers/net/ethernet/renesas/rswitch.h | 42 +++- drivers/net/ethernet/renesas/rswitch_l2.c | 318 ++++++++++++++++++++++++= ++++ drivers/net/ethernet/renesas/rswitch_l2.h | 15 ++ drivers/net/ethernet/renesas/rswitch_main.c | 88 +++++++- 5 files changed, 458 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/r= enesas/Makefile index 6222298bb5582b7091cf8de76acb83ac7dd39c11..d63e0c61bb68a9993d388967aea= 9e1d50f6a95be 100644 --- a/drivers/net/ethernet/renesas/Makefile +++ b/drivers/net/ethernet/renesas/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_SH_ETH) +=3D sh_eth.o ravb-objs :=3D ravb_main.o ravb_ptp.o obj-$(CONFIG_RAVB) +=3D ravb.o =20 -rswitch-objs :=3D rswitch_main.o +rswitch-objs :=3D rswitch_main.o rswitch_l2.o obj-$(CONFIG_RENESAS_ETHER_SWITCH) +=3D rswitch.o =20 obj-$(CONFIG_RENESAS_GEN4_PTP) +=3D rcar_gen4_ptp.o diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/= renesas/rswitch.h index 532192cbca4b520e06a7e35653929d8364f1ccb2..45a9d02c5b5d3e7b62554bd56c6= c0cb9231f684c 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -1,19 +1,25 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Renesas Ethernet Switch device driver * - * Copyright (C) 2022 Renesas Electronics Corporation + * Copyright (C) 2022-2025 Renesas Electronics Corporation */ =20 #ifndef __RSWITCH_H__ #define __RSWITCH_H__ =20 #include +#include + #include "rcar_gen4_ptp.h" =20 #define RSWITCH_MAX_NUM_QUEUES 128 =20 #define RSWITCH_NUM_AGENTS 5 #define RSWITCH_NUM_PORTS 3 + +#define rswitch_for_all_ports(_priv, _rdev) \ + list_for_each_entry(_rdev, &_priv->port_list, list) + #define rswitch_for_each_enabled_port(priv, i) \ for (i =3D 0; i < RSWITCH_NUM_PORTS; i++) \ if (priv->rdev[i]->disabled) \ @@ -809,7 +815,8 @@ enum rswitch_gwca_mode { #define FWPC0_IP4EA BIT(10) #define FWPC0_IPDSA BIT(12) #define FWPC0_IPHLA BIT(18) -#define FWPC0_MACSDA BIT(20) +#define FWPC0_MACDSA BIT(20) +#define FWPC0_MACSSA BIT(23) #define FWPC0_MACHLA BIT(26) #define FWPC0_MACHMA BIT(27) #define FWPC0_VLANSA BIT(28) @@ -821,11 +828,28 @@ enum rswitch_gwca_mode { #define FWPC2(i) (FWPC20 + (i) * 0x10) #define FWCP2_LTWFW GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16) =20 +#define FWCP2_LTWFW_MASK GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16) #define FWPBFC(i) (FWPBFC0 + (i) * 0x10) #define FWPBFC_PBDV GENMASK(RSWITCH_NUM_AGENTS - 1, 0) =20 #define FWPBFCSDC(j, i) (FWPBFCSDC00 + (i) * 0x10 + (j) * 0x04) =20 +#define FWMACHEC_MACHMUE_MASK GENMASK(26, 16) + +#define FWMACTIM_MACTIOG BIT(0) +#define FWMACTIM_MACTR BIT(1) + +#define FWMACAGUSPC_MACAGUSP GENMASK(9, 0) +#define FWMACAGC_MACAGT GENMASK(15, 0) +#define FWMACAGC_MACAGE BIT(16) +#define FWMACAGC_MACAGSL BIT(17) +#define FWMACAGC_MACAGPM BIT(18) +#define FWMACAGC_MACDES BIT(24) +#define FWMACAGC_MACAGOG BIT(28) +#define FWMACAGC_MACDESOG BIT(29) + +#define RSW_AGEING_TIME 300 + /* TOP */ #define TPEMIMC7(queue) (TPEMIMC70 + (queue) * 4) =20 @@ -994,10 +1018,18 @@ struct rswitch_device { DECLARE_BITMAP(ts_skb_used, TS_TAGS_PER_PORT); bool disabled; =20 + struct list_head list; + int port; struct rswitch_etha *etha; struct device_node *np_port; struct phy *serdes; + + struct net_device *brdev; /* master bridge device */ + unsigned int learning_requested : 1; + unsigned int learning_offloaded : 1; + unsigned int forwarding_requested : 1; + unsigned int forwarding_offloaded : 1; }; =20 struct rswitch_mfwd_mac_table_entry { @@ -1022,11 +1054,17 @@ struct rswitch_private { struct rswitch_etha etha[RSWITCH_NUM_PORTS]; struct rswitch_mfwd mfwd; =20 + struct list_head port_list; + spinlock_t lock; /* lock interrupt registers' control */ struct clk *clk; =20 bool etha_no_runtime_change; bool gwca_halt; + struct net_device *offload_brdev; }; =20 +bool is_rdev(const struct net_device *ndev); +void rswitch_modify(void __iomem *addr, enum rswitch_reg reg, u32 clear, u= 32 set); + #endif /* #ifndef __RSWITCH_H__ */ diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethern= et/renesas/rswitch_l2.c new file mode 100644 index 0000000000000000000000000000000000000000..242beb1f15c089585f5fe5019f6= 26df8824b971a --- /dev/null +++ b/drivers/net/ethernet/renesas/rswitch_l2.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Renesas Ethernet Switch device driver + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include + +#include "rswitch.h" +#include "rswitch_l2.h" + +static bool rdev_for_l2_offload(struct rswitch_device *rdev) +{ + return rdev->priv->offload_brdev && + rdev->brdev =3D=3D rdev->priv->offload_brdev && + (test_bit(rdev->port, rdev->priv->opened_ports)); +} + +void rswitch_update_l2_offload(struct rswitch_private *priv) +{ + bool learning_needed, forwarding_needed; + unsigned int all_ports_mask, fwd_mask; + struct rswitch_device *rdev; + + /* calculate fwd_mask with zeroes in bits corresponding to ports that + * shall participate in hardware forwarding + */ + all_ports_mask =3D GENMASK(RSWITCH_NUM_AGENTS - 1, 0); + fwd_mask =3D all_ports_mask; + + rswitch_for_all_ports(priv, rdev) { + if (rdev_for_l2_offload(rdev) && rdev->forwarding_requested) + fwd_mask &=3D ~BIT(rdev->port); + } + + rswitch_for_all_ports(priv, rdev) { + if (rdev_for_l2_offload(rdev)) { + learning_needed =3D rdev->learning_requested; + forwarding_needed =3D rdev->forwarding_requested; + } else { + learning_needed =3D false; + forwarding_needed =3D false; + } + + if (!rdev->learning_offloaded && learning_needed) { + rswitch_modify(priv->addr, FWPC0(rdev->port), + 0, + FWPC0_MACSSA | FWPC0_MACHLA | FWPC0_MACHMA); + + rdev->learning_offloaded =3D true; + netdev_info(rdev->ndev, "starting hw learning\n"); + } + + if (rdev->learning_offloaded && !learning_needed) { + rswitch_modify(priv->addr, FWPC0(rdev->port), + FWPC0_MACSSA | FWPC0_MACHLA | FWPC0_MACHMA, + 0); + + rdev->learning_offloaded =3D false; + netdev_info(rdev->ndev, "stopping hw learning\n"); + } + + if (forwarding_needed) { + /* Update allowed offload destinations even for ports + * with L2 offload enabled earlier. + * + * Do not allow L2 forwarding to self for hw port. + */ + iowrite32(FIELD_PREP(FWCP2_LTWFW_MASK, fwd_mask | BIT(rdev->port)), + priv->addr + FWPC2(rdev->port)); + + if (!rdev->forwarding_offloaded) { + rswitch_modify(priv->addr, FWPC0(rdev->port), + 0, + FWPC0_MACDSA); + + rdev->forwarding_offloaded =3D true; + netdev_info(rdev->ndev, + "starting hw forwarding\n"); + } + } else if (rdev->forwarding_offloaded) { + iowrite32(FIELD_PREP(FWCP2_LTWFW_MASK, fwd_mask | BIT(rdev->port)), + priv->addr + FWPC2(rdev->port)); + + rswitch_modify(priv->addr, FWPC0(rdev->port), + FWPC0_MACDSA, + 0); + + rdev->forwarding_offloaded =3D false; + netdev_info(rdev->ndev, "stopping hw forwarding\n"); + } + } +} + +static void rswitch_update_offload_brdev(struct rswitch_private *priv, + bool force_update_l2_offload) +{ + struct net_device *offload_brdev =3D NULL; + struct rswitch_device *rdev, *rdev2; + + rswitch_for_all_ports(priv, rdev) { + if (!rdev->brdev) + continue; + rswitch_for_all_ports(priv, rdev2) { + if (rdev2 =3D=3D rdev) + break; + if (rdev2->brdev =3D=3D rdev->brdev) { + offload_brdev =3D rdev->brdev; + break; + } + } + if (offload_brdev) + break; + } + + if (offload_brdev =3D=3D priv->offload_brdev) { + if (offload_brdev && force_update_l2_offload) + rswitch_update_l2_offload(priv); + return; + } + + if (offload_brdev && !priv->offload_brdev) + dev_info(&priv->pdev->dev, "starting l2 offload for %s\n", + netdev_name(offload_brdev)); + else if (!offload_brdev && priv->offload_brdev) + dev_info(&priv->pdev->dev, "stopping l2 offload for %s\n", + netdev_name(priv->offload_brdev)); + else + dev_info(&priv->pdev->dev, + "changing l2 offload from %s to %s\n", + netdev_name(priv->offload_brdev), + netdev_name(offload_brdev)); + + priv->offload_brdev =3D offload_brdev; + + rswitch_update_l2_offload(priv); +} + +static bool rswitch_port_check(const struct net_device *ndev) +{ + return is_rdev(ndev); +} + +static void rswitch_port_update_brdev(struct net_device *ndev, + struct net_device *brdev) +{ + struct rswitch_device *rdev; + + if (!is_rdev(ndev)) + return; + + rdev =3D netdev_priv(ndev); + rdev->brdev =3D brdev; + rswitch_update_offload_brdev(rdev->priv, false); +} + +static int rswitch_port_update_stp_state(struct net_device *ndev, u8 stp_s= tate) +{ + struct rswitch_device *rdev; + + if (!is_rdev(ndev)) + return -ENODEV; + + rdev =3D netdev_priv(ndev); + rdev->learning_requested =3D (stp_state =3D=3D BR_STATE_LEARNING || + stp_state =3D=3D BR_STATE_FORWARDING); + rdev->forwarding_requested =3D (stp_state =3D=3D BR_STATE_FORWARDING); + rswitch_update_l2_offload(rdev->priv); + + return 0; +} + +static int rswitch_netdevice_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *ndev =3D netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info; + struct net_device *brdev; + + if (!rswitch_port_check(ndev)) + return NOTIFY_DONE; + if (event !=3D NETDEV_CHANGEUPPER) + return NOTIFY_DONE; + + info =3D ptr; + + if (netif_is_bridge_master(info->upper_dev)) { + brdev =3D info->linking ? info->upper_dev : NULL; + rswitch_port_update_brdev(ndev, brdev); + } + + return NOTIFY_OK; +} + +static int rswitch_port_attr_set(struct net_device *ndev, const void *ctx, + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) +{ + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + return rswitch_port_update_stp_state(ndev, attr->u.stp_state); + default: + return -EOPNOTSUPP; + } +} + +static int rswitch_port_obj_add(struct net_device *ndev, const void *ctx, + const struct switchdev_obj *obj, + struct netlink_ext_ack *extack) +{ + return -EOPNOTSUPP; +} + +static int rswitch_port_obj_del(struct net_device *ndev, const void *ctx, + const struct switchdev_obj *obj) +{ + return -EOPNOTSUPP; +} + +static int rswitch_switchdev_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *ndev =3D switchdev_notifier_info_to_dev(ptr); + int ret; + + if (event =3D=3D SWITCHDEV_PORT_ATTR_SET) { + ret =3D switchdev_handle_port_attr_set(ndev, ptr, + rswitch_port_check, + rswitch_port_attr_set); + return notifier_from_errno(ret); + } + + if (!rswitch_port_check(ndev)) + return NOTIFY_DONE; + + return notifier_from_errno(-EOPNOTSUPP); +} + +static int rswitch_switchdev_blocking_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *ndev =3D switchdev_notifier_info_to_dev(ptr); + int ret; + + switch (event) { + case SWITCHDEV_PORT_OBJ_ADD: + ret =3D switchdev_handle_port_obj_add(ndev, ptr, + rswitch_port_check, + rswitch_port_obj_add); + break; + case SWITCHDEV_PORT_OBJ_DEL: + ret =3D switchdev_handle_port_obj_del(ndev, ptr, + rswitch_port_check, + rswitch_port_obj_del); + break; + case SWITCHDEV_PORT_ATTR_SET: + ret =3D switchdev_handle_port_attr_set(ndev, ptr, + rswitch_port_check, + rswitch_port_attr_set); + break; + default: + if (!rswitch_port_check(ndev)) + return NOTIFY_DONE; + ret =3D -EOPNOTSUPP; + } + + return notifier_from_errno(ret); +} + +static struct notifier_block rswitch_netdevice_nb =3D { + .notifier_call =3D rswitch_netdevice_event, +}; + +static struct notifier_block rswitch_switchdev_nb =3D { + .notifier_call =3D rswitch_switchdev_event, +}; + +static struct notifier_block rswitch_switchdev_blocking_nb =3D { + .notifier_call =3D rswitch_switchdev_blocking_event, +}; + +int rswitch_register_notifiers(void) +{ + int ret; + + ret =3D register_netdevice_notifier(&rswitch_netdevice_nb); + if (ret) + goto register_netdevice_notifier_failed; + + ret =3D register_switchdev_notifier(&rswitch_switchdev_nb); + if (ret) + goto register_switchdev_notifier_failed; + + ret =3D register_switchdev_blocking_notifier(&rswitch_switchdev_blocking_= nb); + if (ret) + goto register_switchdev_blocking_notifier_failed; + + return 0; + +register_switchdev_blocking_notifier_failed: + unregister_switchdev_notifier(&rswitch_switchdev_nb); +register_switchdev_notifier_failed: + unregister_netdevice_notifier(&rswitch_netdevice_nb); +register_netdevice_notifier_failed: + + return ret; +} + +void rswitch_unregister_notifiers(void) +{ + unregister_switchdev_blocking_notifier(&rswitch_switchdev_blocking_nb); + unregister_switchdev_notifier(&rswitch_switchdev_nb); + unregister_netdevice_notifier(&rswitch_netdevice_nb); +} diff --git a/drivers/net/ethernet/renesas/rswitch_l2.h b/drivers/net/ethern= et/renesas/rswitch_l2.h new file mode 100644 index 0000000000000000000000000000000000000000..57050ede8f31848cde5a497811a= 6ee1b60dedc65 --- /dev/null +++ b/drivers/net/ethernet/renesas/rswitch_l2.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Renesas Ethernet Switch device driver + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#ifndef __RSWITCH_L2_H__ +#define __RSWITCH_L2_H__ + +void rswitch_update_l2_offload(struct rswitch_private *priv); + +int rswitch_register_notifiers(void); +void rswitch_unregister_notifiers(void); + +#endif /* #ifndef __RSWITCH_L2_H__ */ diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethe= rnet/renesas/rswitch_main.c index aba772e14555d30891dc74a5a123121dad77e92b..12689530e09385b7912b25fa1b9= 82bfd637948d4 100644 --- a/drivers/net/ethernet/renesas/rswitch_main.c +++ b/drivers/net/ethernet/renesas/rswitch_main.c @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 /* Renesas Ethernet Switch device driver * - * Copyright (C) 2022 Renesas Electronics Corporation + * Copyright (C) 2022-2025 Renesas Electronics Corporation */ =20 #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -25,6 +28,7 @@ #include =20 #include "rswitch.h" +#include "rswitch_l2.h" =20 static int rswitch_reg_wait(void __iomem *addr, u32 offs, u32 mask, u32 ex= pected) { @@ -34,7 +38,7 @@ static int rswitch_reg_wait(void __iomem *addr, u32 offs,= u32 mask, u32 expected 1, RSWITCH_TIMEOUT_US); } =20 -static void rswitch_modify(void __iomem *addr, enum rswitch_reg reg, u32 c= lear, u32 set) +void rswitch_modify(void __iomem *addr, enum rswitch_reg reg, u32 clear, u= 32 set) { iowrite32((ioread32(addr + reg) & ~clear) | set, addr + reg); } @@ -109,10 +113,12 @@ static void rswitch_top_init(struct rswitch_private *= priv) } =20 /* Forwarding engine block (MFWD) */ -static void rswitch_fwd_init(struct rswitch_private *priv) +static int rswitch_fwd_init(struct rswitch_private *priv) { u32 all_ports_mask =3D GENMASK(RSWITCH_NUM_AGENTS - 1, 0); unsigned int i; + u32 reg_val; + u32 ret; =20 /* Start with empty configuration */ for (i =3D 0; i < RSWITCH_NUM_AGENTS; i++) { @@ -128,6 +134,14 @@ static void rswitch_fwd_init(struct rswitch_private *p= riv) iowrite32(0, priv->addr + FWPBFC(i)); } =20 + /* Configure MAC table aging */ + rswitch_modify(priv->addr, FWMACAGUSPC, FWMACAGUSPC_MACAGUSP, + FIELD_PREP(FWMACAGUSPC_MACAGUSP, 0x140)); + + reg_val =3D FIELD_PREP(FWMACAGC_MACAGT, RSW_AGEING_TIME); + reg_val |=3D FWMACAGC_MACAGE | FWMACAGC_MACAGSL; + iowrite32(reg_val, priv->addr + FWMACAGC); + /* For enabled ETHA ports, setup port based forwarding */ rswitch_for_each_enabled_port(priv, i) { /* Port based forwarding from port i to GWCA port */ @@ -140,6 +154,17 @@ static void rswitch_fwd_init(struct rswitch_private *p= riv) =20 /* For GWCA port, allow direct descriptor forwarding */ rswitch_modify(priv->addr, FWPC1(priv->gwca.index), FWPC1_DDE, FWPC1_DDE); + + /* Initialize hardware L2 forwarding table */ + + /* Allow entire table to be used for "unsecure" entries */ + rswitch_modify(priv->addr, FWMACHEC, 0, FWMACHEC_MACHMUE_MASK); + + /* Initialize MAC hash table */ + iowrite32(FWMACTIM_MACTIOG, priv->addr + FWMACTIM); + ret =3D rswitch_reg_wait(priv->addr, FWMACTIM, FWMACTIM_MACTIOG, 0); + + return ret; } =20 /* Gateway CPU agent block (GWCA) */ @@ -1602,6 +1627,9 @@ static int rswitch_open(struct net_device *ndev) =20 netif_start_queue(ndev); =20 + if (rdev->brdev) + rswitch_update_l2_offload(rdev->priv); + return 0; }; =20 @@ -1624,6 +1652,9 @@ static int rswitch_stop(struct net_device *ndev) =20 napi_disable(&rdev->napi); =20 + if (rdev->brdev) + rswitch_update_l2_offload(rdev->priv); + if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID); =20 @@ -1850,16 +1881,46 @@ static int rswitch_eth_ioctl(struct net_device *nde= v, struct ifreq *req, int cmd } } =20 +static int rswitch_get_port_parent_id(struct net_device *ndev, + struct netdev_phys_item_id *ppid) +{ + struct rswitch_device *rdev =3D netdev_priv(ndev); + const char *name; + + name =3D dev_name(&rdev->priv->pdev->dev); + ppid->id_len =3D min_t(size_t, strlen(name), sizeof(ppid->id_len)); + memcpy(ppid->id, name, ppid->id_len); + + return 0; +} + +static int rswitch_get_phys_port_name(struct net_device *ndev, + char *name, size_t len) +{ + struct rswitch_device *rdev =3D netdev_priv(ndev); + + snprintf(name, len, "tsn%d", rdev->port); + + return 0; +} + static const struct net_device_ops rswitch_netdev_ops =3D { .ndo_open =3D rswitch_open, .ndo_stop =3D rswitch_stop, .ndo_start_xmit =3D rswitch_start_xmit, .ndo_get_stats =3D rswitch_get_stats, .ndo_eth_ioctl =3D rswitch_eth_ioctl, + .ndo_get_port_parent_id =3D rswitch_get_port_parent_id, + .ndo_get_phys_port_name =3D rswitch_get_phys_port_name, .ndo_validate_addr =3D eth_validate_addr, .ndo_set_mac_address =3D eth_mac_addr, }; =20 +bool is_rdev(const struct net_device *ndev) +{ + return (ndev->netdev_ops =3D=3D &rswitch_netdev_ops); +} + static int rswitch_get_ts_info(struct net_device *ndev, struct kernel_etht= ool_ts_info *info) { struct rswitch_device *rdev =3D netdev_priv(ndev); @@ -1959,6 +2020,8 @@ static int rswitch_device_alloc(struct rswitch_privat= e *priv, unsigned int index if (err < 0) goto out_txdmac; =20 + list_add_tail(&rdev->list, &priv->port_list); + return 0; =20 out_txdmac: @@ -1978,6 +2041,7 @@ static void rswitch_device_free(struct rswitch_privat= e *priv, unsigned int index struct rswitch_device *rdev =3D priv->rdev[index]; struct net_device *ndev =3D rdev->ndev; =20 + list_del(&rdev->list); rswitch_txdmac_free(ndev); rswitch_rxdmac_free(ndev); of_node_put(rdev->np_port); @@ -2024,7 +2088,9 @@ static int rswitch_init(struct rswitch_private *priv) } } =20 - rswitch_fwd_init(priv); + err =3D rswitch_fwd_init(priv); + if (err < 0) + goto err_fwd_init; =20 err =3D rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT, clk_get_rate(priv->clk)); @@ -2073,6 +2139,7 @@ static int rswitch_init(struct rswitch_private *priv) err_gwca_request_irq: rcar_gen4_ptp_unregister(priv->ptp_priv); =20 +err_fwd_init: err_ptp_register: for (i =3D 0; i < RSWITCH_NUM_PORTS; i++) rswitch_device_free(priv, i); @@ -2107,6 +2174,7 @@ static int renesas_eth_sw_probe(struct platform_devic= e *pdev) priv =3D devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + spin_lock_init(&priv->lock); =20 priv->clk =3D devm_clk_get(&pdev->dev, NULL); @@ -2144,6 +2212,8 @@ static int renesas_eth_sw_probe(struct platform_devic= e *pdev) if (!priv->gwca.queues) return -ENOMEM; =20 + INIT_LIST_HEAD(&priv->port_list); + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); =20 @@ -2154,6 +2224,15 @@ static int renesas_eth_sw_probe(struct platform_devi= ce *pdev) return ret; } =20 + if (list_empty(&priv->port_list)) + dev_warn(&pdev->dev, "could not initialize any ports\n"); + + ret =3D rswitch_register_notifiers(); + if (ret) { + dev_err(&pdev->dev, "could not register notifiers\n"); + return ret; + } + device_set_wakeup_capable(&pdev->dev, 1); =20 return ret; @@ -2187,6 +2266,7 @@ static void renesas_eth_sw_remove(struct platform_dev= ice *pdev) { struct rswitch_private *priv =3D platform_get_drvdata(pdev); =20 + rswitch_unregister_notifiers(); rswitch_deinit(priv); =20 pm_runtime_put(&pdev->dev); --=20 2.49.0 From nobody Tue Oct 7 22:58:39 2025 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 55489223DC0; Fri, 4 Jul 2025 05:51:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608307; cv=none; b=Zv6SYpw5aYvfi0m6dGjb7P8yZS303eJPF4OFEeAkQND2tTWPmm+LRNYTQ6a7gXAtaxKpACr2oq+Gs9gKvJ3Pgb3oixBB5Czj/HEp1S8gvBRnuTGaT+popkxpvWe68/lCOoPm1sdL3nYfGQ1/UVVeWZK7FIxW1InzRgOCSsqoYGo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751608307; c=relaxed/simple; bh=TMWAIH48ZhOH7NcIlTEmJSZsLzicki8S75hRqhPlV9U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ACMerdAQQ5w0I94PzWO5tfRkE6QyiWAjsN8yqSf6pvPy0vAPAbkiC7T9YBSuuqQRfkLGaA3KQVDoAUDVXx4hAGRLZ8lTgN82kh9t83N6fek6ZdsTGuPhcwCZdY34MbDlA4U0sBfDxYct6AjY7nS6S3SbtcY+SmpIXs4zVs+NEu8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com; spf=pass smtp.mailfrom=renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=renesas.com X-CSE-ConnectionGUID: EK1Xbw1tREu7VA75XdcRJw== X-CSE-MsgGUID: y+RZrP1cRCiwhoY62piNjQ== Received: from unknown (HELO relmlir6.idc.renesas.com) ([10.200.68.152]) by relmlie6.idc.renesas.com with ESMTP; 04 Jul 2025 14:51:44 +0900 Received: from [127.0.1.1] (unknown [10.226.78.19]) by relmlir6.idc.renesas.com (Postfix) with ESMTP id 91E8F4156F90; Fri, 4 Jul 2025 14:51:40 +0900 (JST) From: Michael Dege Date: Fri, 04 Jul 2025 07:51:17 +0200 Subject: [PATCH 3/3] net: renesas: rswitch: add modifiable ageing time Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250704-add_l2_switching-v1-3-ff882aacb258@renesas.com> References: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> In-Reply-To: <20250704-add_l2_switching-v1-0-ff882aacb258@renesas.com> To: Yoshihiro Shimoda , =?utf-8?q?Niklas_S=C3=B6derlund?= , Paul Barker , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Michael Dege , Nikita Yushchenko X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1751608288; l=2498; i=michael.dege@renesas.com; s=20250523; h=from:subject:message-id; bh=TMWAIH48ZhOH7NcIlTEmJSZsLzicki8S75hRqhPlV9U=; b=zX9H68pRwkNotk+Npq3JXSDc3yBIbR+gWBVGqQsS2PTTv8crg1VGEs8dTfVPXw56CG7LN/900 aKqFzB7Lsf5BkktBkQKcQ8wuUjOIGPd6KEn2Rww9e/g1py1015r0plk X-Developer-Key: i=michael.dege@renesas.com; a=ed25519; pk=+gYTlVQ3/MlOju88OuKnXA7MlapP4lYqJn1F81HZGSo= This commit allows the setting of the MAC table aging in the R-Car S4 Rswitch using the SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME attribute. Signed-off-by: Michael Dege --- drivers/net/ethernet/renesas/rswitch.h | 1 + drivers/net/ethernet/renesas/rswitch_l2.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/= renesas/rswitch.h index 45a9d02c5b5d3e7b62554bd56c6c0cb9231f684c..11ff1102668b081e395664ea73e= 19e0ecef74e24 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -849,6 +849,7 @@ enum rswitch_gwca_mode { #define FWMACAGC_MACDESOG BIT(29) =20 #define RSW_AGEING_TIME 300 +#define RSW_MAX_AGEING_TIME 65535 =20 /* TOP */ #define TPEMIMC7(queue) (TPEMIMC70 + (queue) * 4) diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethern= et/renesas/rswitch_l2.c index 242beb1f15c089585f5fe5019f626df8824b971a..c8a8a60a20e70f7ce421280ed35= c0c4afe1ed039 100644 --- a/drivers/net/ethernet/renesas/rswitch_l2.c +++ b/drivers/net/ethernet/renesas/rswitch_l2.c @@ -196,6 +196,30 @@ static int rswitch_netdevice_event(struct notifier_blo= ck *nb, return NOTIFY_OK; } =20 +static int rswitch_update_ageing_time(struct net_device *ndev, clock_t tim= e) +{ + struct rswitch_device *rdev =3D netdev_priv(ndev); + u32 reg_val, time_val; + + if (!is_rdev(ndev)) + return -ENODEV; + + /* Although brctl accepts the ageing time parameter in seconds, the value + * passed to the driver is multiplied by 100. We need it in seconds. + */ + time_val =3D (u32)time / 100; + + if (time_val > RSW_MAX_AGEING_TIME) + return -EINVAL; + + rdev =3D netdev_priv(ndev); + reg_val =3D FIELD_PREP(FWMACAGC_MACAGT, time_val); + reg_val |=3D FWMACAGC_MACAGE | FWMACAGC_MACAGSL; + iowrite32(reg_val, rdev->priv->addr + FWMACAGC); + + return 0; +} + static int rswitch_port_attr_set(struct net_device *ndev, const void *ctx, const struct switchdev_attr *attr, struct netlink_ext_ack *extack) @@ -203,6 +227,8 @@ static int rswitch_port_attr_set(struct net_device *nde= v, const void *ctx, switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: return rswitch_port_update_stp_state(ndev, attr->u.stp_state); + case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: + return rswitch_update_ageing_time(ndev, attr->u.ageing_time); default: return -EOPNOTSUPP; } --=20 2.49.0