From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [80.241.56.171]) (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 8BDCC2E1751 for ; Sun, 24 Aug 2025 22:08:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=80.241.56.171 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756073314; cv=none; b=pwZ2o7RS1qSbbxu64twrZd8BHJIRpnmYsSSYB3P7zNz+tY4aFKcvH5nS6ieRJGckAOvaLZ4JagN37tcU6mJSCSdo6lYd1sJ+uJcIOyPJXqvtaecLQll4/rk7/HqnVQMN8xW38hWic+noaawJg0VUwUFAvGGW9Gqp9CDdbzr8FnA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756073314; c=relaxed/simple; bh=M/AR9G71oXMKFU4GWfLgE1SjKg9L5M2Tk+00V49EVh8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=aHTuIVvEue9gaiO+YJ/Hc5vP8zcgpVKh8yEJxHrSHrdWz3shfp0/DeE+ZpItwpqTCtvQObXqFlNAVhefxKwqi63G1wmkgdPyO+i7hcBuMJN8rQQXrypdl1/gVX9DOi4ZRc4TyRpkWW797v7NK3k3pLCUXWM/9MP1+FMIgTRGIw8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=mailbox.org; spf=pass smtp.mailfrom=mailbox.org; dkim=pass (2048-bit key) header.d=mailbox.org header.i=@mailbox.org header.b=h47dp1M7; dkim=pass (2048-bit key) header.d=mailbox.org header.i=@mailbox.org header.b=GDhLZ0G0; arc=none smtp.client-ip=80.241.56.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=mailbox.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mailbox.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mailbox.org header.i=@mailbox.org header.b="h47dp1M7"; dkim=pass (2048-bit key) header.d=mailbox.org header.i=@mailbox.org header.b="GDhLZ0G0" Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4c97NY6fcyz9slX; Mon, 25 Aug 2025 00:08:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1756073310; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6umtjRPfHeJ2FE3vhtFkE6vLDAyeVOWf9VX14vEe+HE=; b=h47dp1M7loNiEG1jIWjp9tZPM2NCu7Qz8Pv3UlCeg4GXYBTH3TJM+KZ/7DHHJPz4nbMxyz oK2m4HsJZayN4HfcR1+xffp7yuzaCWsClq8W5TsKy9xHDDlooCvrJezrG8N4W6mTLZVpcE 8gcYiWA2EEYD4pu+k3hcCJ3vHmlzz1nR3bmKj2iCIdSD1ZsF8KwHjV3HLc1e6yfJoSsVDJ kxs9lJYyC5t/CdqhdtsoKEQ8TGdXIw6Mr/gFIgMEfo0UpRGH6N54aFVT/Muo6IPxAiVrMe H7tGiFFiGXOCC8HFp0ohhOgOub5MBDW/2mVh5sSXxpLuF+/VtU3kwtB/MwaGgg== Authentication-Results: outgoing_mbo_mout; dkim=pass header.d=mailbox.org header.s=mail20150812 header.b=GDhLZ0G0; spf=pass (outgoing_mbo_mout: domain of lukasz.majewski@mailbox.org designates 2001:67c:2050:b231:465::102 as permitted sender) smtp.mailfrom=lukasz.majewski@mailbox.org From: Lukasz Majewski DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1756073308; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6umtjRPfHeJ2FE3vhtFkE6vLDAyeVOWf9VX14vEe+HE=; b=GDhLZ0G0+Qgs3jP4Kvyg/Aivp9LFlpg7PQhomWkfTERpTJUqPTv2xqm3OACwKEW0j3h8R3 DSc51RfW0rlZ3UmswSnOCujRRAN0Dg0vGl0xe+JWCFBdITrHM96rz+5IdAkd1IQuJ0c1h8 y7ytASwRGOyX6nWkj4eSHUJlysNUseTAzVemuGiotHxM1VOBRM+2f49KgKMZrEFvySkFFL 8Rx2fmBg3yHySvqUDCzGkNAwc8gzIJfQsak2Y3mLsjfUg1In6oCXwf6dF1AF4rrRhVYpHI tbRcFFH5MDOPN2TButdJwxxE9pvKVPSelJ4WA7IEu2HmYHM6WXj4mDI357Tfew== 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 v19 6/7] net: mtip: Extend the L2 switch driver with management operations Date: Mon, 25 Aug 2025 00:07:35 +0200 Message-Id: <20250824220736.1760482-7-lukasz.majewski@mailbox.org> In-Reply-To: <20250824220736.1760482-1-lukasz.majewski@mailbox.org> References: <20250824220736.1760482-1-lukasz.majewski@mailbox.org> Precedence: bulk X-Mailing-List: imx@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-MBO-RS-ID: c1285aa20ab99cc1a36 X-MBO-RS-META: gt3ha95tzpmhegwkhgtuebkarr1jfjhf X-Rspamd-Queue-Id: 4c97NY6fcyz9slX This patch provides function necessary for manging the L2 switch. 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 - v19: - None --- .../net/ethernet/freescale/mtipsw/Makefile | 2 +- .../net/ethernet/freescale/mtipsw/mtipl2sw.c | 31 ++ .../net/ethernet/freescale/mtipsw/mtipl2sw.h | 23 + .../ethernet/freescale/mtipsw/mtipl2sw_mgnt.c | 443 ++++++++++++++++++ 4 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw_mgnt.c diff --git a/drivers/net/ethernet/freescale/mtipsw/Makefile b/drivers/net/ethernet/freescale/mtipsw/Makefile index bd8ffb30939a..a99aaf6ddfb2 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 +nxp-mtipl2sw-objs := mtipl2sw.o mtipl2sw_mgnt.o diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c index 0d97b33c4f2c..fe694d5b6863 100644 --- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c @@ -474,8 +474,35 @@ static void mtip_config_switch(struct switch_enet_private *fep) writel(0, fep->hwp + ESW_BKLR); + /* Do NOT disable learning */ + mtip_port_learning_config(fep, 0, 0, 0); + mtip_port_learning_config(fep, 1, 0, 0); + mtip_port_learning_config(fep, 2, 0, 0); + + /* Disable blocking */ + mtip_port_blocking_config(fep, 0, 0); + mtip_port_blocking_config(fep, 1, 0); + mtip_port_blocking_config(fep, 2, 0); + writel(MCF_ESW_IMR_TXF | MCF_ESW_IMR_RXF, fep->hwp + ESW_IMR); + + mtip_port_enable_config(fep, 0, 1, 1); + mtip_port_enable_config(fep, 1, 1, 1); + mtip_port_enable_config(fep, 2, 1, 1); + + mtip_port_broadcast_config(fep, 0, 1); + mtip_port_broadcast_config(fep, 1, 1); + mtip_port_broadcast_config(fep, 2, 1); + + /* Disable multicast receive on port 0 (MGNT) */ + mtip_port_multicast_config(fep, 0, 0); + mtip_port_multicast_config(fep, 1, 1); + mtip_port_multicast_config(fep, 2, 1); + + /* Setup VLANs to provide port separation */ + if (!fep->br_offload) + mtip_switch_en_port_separation(fep); } static netdev_tx_t mtip_start_xmit_port(struct sk_buff *skb, @@ -564,6 +591,10 @@ static netdev_tx_t mtip_start_xmit_port(struct sk_buff *skb, skb_tx_timestamp(skb); + /* For port separation - force sending via specified port */ + if (!fep->br_offload && port != 0) + mtip_forced_forward(fep, port, 1); + /* Trigger transmission start */ writel(MCF_ESW_TDAR_X_DES_ACTIVE, fep->hwp + ESW_TDAR); diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h index 8a3cce976476..7e5373823d43 100644 --- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h @@ -621,6 +621,29 @@ static inline int mtip_get_time(void) #define MTIP_PORT_FORWARDING_INIT 0xFF +/* Switch Management functions */ +int mtip_vlan_input_process(struct switch_enet_private *fep, + int port, int mode, unsigned short port_vlanid, + int vlan_verify_en, int vlan_domain_num, + int vlan_domain_port); +int mtip_set_vlan_verification(struct switch_enet_private *fep, int port, + int vlan_domain_verify_en, + int vlan_discard_unknown_en); +int mtip_port_multicast_config(struct switch_enet_private *fep, int port, + bool enable); +int mtip_vlan_output_process(struct switch_enet_private *fep, int port, + int mode); +void mtip_switch_en_port_separation(struct switch_enet_private *fep); +void mtip_switch_dis_port_separation(struct switch_enet_private *fep); +int mtip_port_broadcast_config(struct switch_enet_private *fep, + int port, bool enable); +int mtip_forced_forward(struct switch_enet_private *fep, int port, bool enable); +int mtip_port_learning_config(struct switch_enet_private *fep, int port, + bool disable, bool irq_adj); +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_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); #endif /* __MTIP_L2SWITCH_H_ */ diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_mgnt.c b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_mgnt.c new file mode 100644 index 000000000000..2178b3d02d57 --- /dev/null +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw_mgnt.c @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * L2 switch Controller driver for MTIP block - switch MGNT + * + * Copyright (C) 2025 DENX Software Engineering GmbH + * Lukasz Majewski + * + * Based on a previous work by: + * + * Copyright 2010-2012 Freescale Semiconductor, Inc. + * Alison Wang (b18965@freescale.com) + * Jason Jin (Jason.jin@freescale.com) + * + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * Shrek Wu (B16972@freescale.com) + */ + +#include +#include +#include + +#include "mtipl2sw.h" + +int mtip_vlan_input_process(struct switch_enet_private *fep, + int port, int mode, unsigned short port_vlanid, + int vlan_verify_en, int vlan_domain_num, + int vlan_domain_port) +{ + /* Only modes from 1 to 4 are valid*/ + if (mode < 0 || mode > 4) { + dev_err(&fep->pdev->dev, + "%s: VLAN input processing mode (%d) not supported\n", + __func__, mode); + return -EINVAL; + } + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported!\n", + __func__, port); + return -EINVAL; + } + + if (vlan_verify_en == 1 && + (vlan_domain_num < 0 || vlan_domain_num > 32)) { + dev_err(&fep->pdev->dev, "%s: Domain out of range\n", __func__); + return -EINVAL; + } + + writel(FIELD_PREP(MCF_ESW_PID_VLANID_MASK, port_vlanid), + fep->hwp + ESW_PID(port)); + if (port == 0) { + if (vlan_verify_en == 1) + writel(FIELD_PREP(MCF_ESW_VRES_VLANID_MASK, + port_vlanid) | MCF_ESW_VRES_P0, + fep->hwp + ESW_VRES(vlan_domain_num)); + + writel(readl(fep->hwp + ESW_VIMEN) | MCF_ESW_VIMEN_EN0, + fep->hwp + ESW_VIMEN); + writel(readl(fep->hwp + ESW_VIMSEL) | + FIELD_PREP(MCF_ESW_VIMSEL_IM0_MASK, mode), + fep->hwp + ESW_VIMSEL); + } else if (port == 1) { + if (vlan_verify_en == 1) + writel(FIELD_PREP(MCF_ESW_VRES_VLANID_MASK, + port_vlanid) | MCF_ESW_VRES_P1, + fep->hwp + ESW_VRES(vlan_domain_num)); + + writel(readl(fep->hwp + ESW_VIMEN) | MCF_ESW_VIMEN_EN1, + fep->hwp + ESW_VIMEN); + writel(readl(fep->hwp + ESW_VIMSEL) | + FIELD_PREP(MCF_ESW_VIMSEL_IM1_MASK, mode), + fep->hwp + ESW_VIMSEL); + } else if (port == 2) { + if (vlan_verify_en == 1) + writel(FIELD_PREP(MCF_ESW_VRES_VLANID_MASK, + port_vlanid) | MCF_ESW_VRES_P2, + fep->hwp + ESW_VRES(vlan_domain_num)); + + writel(readl(fep->hwp + ESW_VIMEN) | MCF_ESW_VIMEN_EN2, + fep->hwp + ESW_VIMEN); + writel(readl(fep->hwp + ESW_VIMSEL) | + FIELD_PREP(MCF_ESW_VIMSEL_IM2_MASK, mode), + fep->hwp + ESW_VIMSEL); + } + + return 0; +} + +int mtip_vlan_output_process(struct switch_enet_private *fep, int port, + int mode) +{ + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported!\n", + __func__, port); + return -EINVAL; + } + + if (port == 0) { + writel(readl(fep->hwp + ESW_VOMSEL) | + FIELD_PREP(MCF_ESW_VOMSEL_OM0_MASK, mode), + fep->hwp + ESW_VOMSEL); + } else if (port == 1) { + writel(readl(fep->hwp + ESW_VOMSEL) | + FIELD_PREP(MCF_ESW_VOMSEL_OM1_MASK, mode), + fep->hwp + ESW_VOMSEL); + } else if (port == 2) { + writel(readl(fep->hwp + ESW_VOMSEL) | + FIELD_PREP(MCF_ESW_VOMSEL_OM2_MASK, mode), + fep->hwp + ESW_VOMSEL); + } + + return 0; +} + +int mtip_set_vlan_verification(struct switch_enet_private *fep, int port, + int vlan_domain_verify_en, + int vlan_discard_unknown_en) +{ + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported!\n", + __func__, port); + return -EINVAL; + } + + if (vlan_domain_verify_en == 1) { + if (port == 0) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_VV0, + fep->hwp + ESW_VLANV); + else if (port == 1) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_VV1, + fep->hwp + ESW_VLANV); + else if (port == 2) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_VV2, + fep->hwp + ESW_VLANV); + } else if (vlan_domain_verify_en == 0) { + if (port == 0) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_VV0, + fep->hwp + ESW_VLANV); + else if (port == 1) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_VV1, + fep->hwp + ESW_VLANV); + else if (port == 2) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_VV2, + fep->hwp + ESW_VLANV); + } + + if (vlan_discard_unknown_en == 1) { + if (port == 0) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_DU0, + fep->hwp + ESW_VLANV); + else if (port == 1) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_DU1, + fep->hwp + ESW_VLANV); + else if (port == 2) + writel(readl(fep->hwp + ESW_VLANV) | MCF_ESW_VLANV_DU2, + fep->hwp + ESW_VLANV); + } else if (vlan_discard_unknown_en == 0) { + if (port == 0) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_DU0, + fep->hwp + ESW_VLANV); + else if (port == 1) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_DU1, + fep->hwp + ESW_VLANV); + else if (port == 2) + writel(readl(fep->hwp + ESW_VLANV) & ~MCF_ESW_VLANV_DU2, + fep->hwp + ESW_VLANV); + } + + dev_dbg(&fep->pdev->dev, "%s: ESW_VLANV %#x\n", __func__, + readl(fep->hwp + ESW_VLANV)); + + return 0; +} + +int mtip_port_multicast_config(struct switch_enet_private *fep, + int port, bool enable) +{ + u32 reg = 0; + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported\n", + __func__, port); + return -EINVAL; + } + + reg = readl(fep->hwp + ESW_DMCR); + if (enable) { + if (port == 0) + reg |= MCF_ESW_DMCR_P0; + else if (port == 1) + reg |= MCF_ESW_DMCR_P1; + else if (port == 2) + reg |= MCF_ESW_DMCR_P2; + } else { + if (port == 0) + reg &= ~MCF_ESW_DMCR_P0; + else if (port == 1) + reg &= ~MCF_ESW_DMCR_P1; + else if (port == 2) + reg &= ~MCF_ESW_DMCR_P2; + } + + writel(reg, fep->hwp + ESW_DMCR); + return 0; +} + +/* enable or disable port n tx or rx + * tx_en 0 disable port n tx + * tx_en 1 enable port n tx + * rx_en 0 disable port n rx + * rx_en 1 enable port n rx + */ +int mtip_port_enable_config(struct switch_enet_private *fep, int port, + bool tx_en, bool rx_en) +{ + u32 reg = 0; + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported\n", + __func__, port); + return -EINVAL; + } + + reg = readl(fep->hwp + ESW_PER); + if (tx_en) { + if (port == 0) + reg |= MCF_ESW_PER_TE0; + else if (port == 1) + reg |= MCF_ESW_PER_TE1; + else if (port == 2) + reg |= MCF_ESW_PER_TE2; + } else { + if (port == 0) + reg &= (~MCF_ESW_PER_TE0); + else if (port == 1) + reg &= (~MCF_ESW_PER_TE1); + else if (port == 2) + reg &= (~MCF_ESW_PER_TE2); + } + + if (rx_en) { + if (port == 0) + reg |= MCF_ESW_PER_RE0; + else if (port == 1) + reg |= MCF_ESW_PER_RE1; + else if (port == 2) + reg |= MCF_ESW_PER_RE2; + } else { + if (port == 0) + reg &= (~MCF_ESW_PER_RE0); + else if (port == 1) + reg &= (~MCF_ESW_PER_RE1); + else if (port == 2) + reg &= (~MCF_ESW_PER_RE2); + } + + writel(reg, fep->hwp + ESW_PER); + return 0; +} + +void mtip_switch_en_port_separation(struct switch_enet_private *fep) +{ + u32 reg; + + mtip_vlan_input_process(fep, 0, 3, 0x10, 1, 0, 0); + mtip_vlan_input_process(fep, 1, 3, 0x11, 1, 1, 0); + mtip_vlan_input_process(fep, 2, 3, 0x12, 1, 2, 0); + + reg = readl(fep->hwp + ESW_VRES(0)); + writel(reg | MCF_ESW_VRES_P1 | MCF_ESW_VRES_P2, + fep->hwp + ESW_VRES(0)); + + reg = readl(fep->hwp + ESW_VRES(1)); + writel(reg | MCF_ESW_VRES_P0, fep->hwp + ESW_VRES(1)); + + reg = readl(fep->hwp + ESW_VRES(2)); + writel(reg | MCF_ESW_VRES_P0, fep->hwp + ESW_VRES(2)); + + dev_dbg(&fep->pdev->dev, "%s: VRES0: 0x%x\n", + __func__, readl(fep->hwp + ESW_VRES(0))); + dev_dbg(&fep->pdev->dev, "%s: VRES1: 0x%x\n", __func__, + readl(fep->hwp + ESW_VRES(1))); + dev_dbg(&fep->pdev->dev, "%s: VRES2: 0x%x\n", __func__, + readl(fep->hwp + ESW_VRES(2))); + + mtip_set_vlan_verification(fep, 0, 1, 0); + mtip_set_vlan_verification(fep, 1, 1, 0); + mtip_set_vlan_verification(fep, 2, 1, 0); + + mtip_vlan_output_process(fep, 0, 2); + mtip_vlan_output_process(fep, 1, 2); + mtip_vlan_output_process(fep, 2, 2); +} + +void mtip_switch_dis_port_separation(struct switch_enet_private *fep) +{ + writel(0, fep->hwp + ESW_PID(0)); + writel(0, fep->hwp + ESW_PID(1)); + writel(0, fep->hwp + ESW_PID(2)); + + writel(0, fep->hwp + ESW_VRES(0)); + writel(0, fep->hwp + ESW_VRES(1)); + writel(0, fep->hwp + ESW_VRES(2)); + + writel(0, fep->hwp + ESW_VIMEN); + writel(0, fep->hwp + ESW_VIMSEL); + writel(0, fep->hwp + ESW_VLANV); + writel(0, fep->hwp + ESW_VOMSEL); +} + +int mtip_port_broadcast_config(struct switch_enet_private *fep, + int port, bool enable) +{ + u32 reg = 0; + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported\n", + __func__, port); + return -EINVAL; + } + + reg = readl(fep->hwp + ESW_DBCR); + if (enable) { + if (port == 0) + reg |= MCF_ESW_DBCR_P0; + else if (port == 1) + reg |= MCF_ESW_DBCR_P1; + else if (port == 2) + reg |= MCF_ESW_DBCR_P2; + } else { + if (port == 0) + reg &= ~MCF_ESW_DBCR_P0; + else if (port == 1) + reg &= ~MCF_ESW_DBCR_P1; + else if (port == 2) + reg &= ~MCF_ESW_DBCR_P2; + } + + writel(reg, fep->hwp + ESW_DBCR); + return 0; +} + +/* The frame is forwarded to the forced destination ports. + * It only replace the MAC lookup function, + * all other filtering(eg.VLAN verification) act as normal + */ +int mtip_forced_forward(struct switch_enet_private *fep, int port, bool enable) +{ + u32 reg = 0; + + if (port & ~GENMASK(1, 0)) { + dev_err(&fep->pdev->dev, + "%s: Forced forward for port(s): 0x%x not supported!\n", + __func__, port); + return -EINVAL; + } + + /* Enable Forced forwarding for port(s) */ + reg |= FIELD_PREP(MCF_ESW_P0FFEN_FD_MASK, port & GENMASK(1, 0)); + + if (enable) + reg |= MCF_ESW_P0FFEN_FEN; + else + reg &= ~MCF_ESW_P0FFEN_FEN; + + writel(reg, fep->hwp + ESW_P0FFEN); + return 0; +} + +int mtip_port_learning_config(struct switch_enet_private *fep, int port, + bool disable, bool irq_adj) +{ + u32 reg = 0; + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported\n", + __func__, port); + return -EINVAL; + } + + reg = readl(fep->hwp + ESW_BKLR); + if (disable) { + if (irq_adj) + writel(readl(fep->hwp + ESW_IMR) & ~MCF_ESW_IMR_LRN, + fep->hwp + ESW_IMR); + + if (port == 0) + reg |= MCF_ESW_BKLR_LD0; + else if (port == 1) + reg |= MCF_ESW_BKLR_LD1; + else if (port == 2) + reg |= MCF_ESW_BKLR_LD2; + } else { + if (irq_adj) + writel(readl(fep->hwp + ESW_IMR) | MCF_ESW_IMR_LRN, + fep->hwp + ESW_IMR); + + if (port == 0) + reg &= ~MCF_ESW_BKLR_LD0; + else if (port == 1) + reg &= ~MCF_ESW_BKLR_LD1; + else if (port == 2) + reg &= ~MCF_ESW_BKLR_LD2; + } + + writel(reg, fep->hwp + ESW_BKLR); + dev_dbg(&fep->pdev->dev, "%s ESW_BKLR %#x, ESW_IMR %#x\n", __func__, + readl(fep->hwp + ESW_BKLR), readl(fep->hwp + ESW_IMR)); + + return 0; +} + +int mtip_port_blocking_config(struct switch_enet_private *fep, int port, + bool enable) +{ + u32 reg = 0; + + if (port < 0 || port > 2) { + dev_err(&fep->pdev->dev, "%s: Port (%d) not supported\n", + __func__, port); + return -EINVAL; + } + + reg = readl(fep->hwp + ESW_BKLR); + if (enable) { + if (port == 0) + reg |= MCF_ESW_BKLR_BE0; + else if (port == 1) + reg |= MCF_ESW_BKLR_BE1; + else if (port == 2) + reg |= MCF_ESW_BKLR_BE2; + } else { + if (port == 0) + reg &= ~MCF_ESW_BKLR_BE0; + else if (port == 1) + reg &= ~MCF_ESW_BKLR_BE1; + else if (port == 2) + reg &= ~MCF_ESW_BKLR_BE2; + } + + writel(reg, fep->hwp + ESW_BKLR); + return 0; +} -- 2.39.5