From patchwork Thu Jan 28 06:41:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12051997 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E756EC433E0 for ; Thu, 28 Jan 2021 06:46:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9EA1164DD6 for ; Thu, 28 Jan 2021 06:46:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231358AbhA1Gpv (ORCPT ); Thu, 28 Jan 2021 01:45:51 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:3043 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbhA1Gpa (ORCPT ); Thu, 28 Jan 2021 01:45:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816329; x=1643352329; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kcXRAuyJ9EzBjv3KtVbdwXLLCjOZ76LBz3uqxTXCFms=; b=X17qqdVC8jj/VEXWMQJIty9wX2aS45CK+GXUzmEyo+krzjONORtJc36x PaQCb+pPujrYFgpRFcUVzjW6quB6wDau7JjpqnKkuK5vSsMMUAaY0EsSn wremAsCf2wtYeL3yx27/kFzgjl8C4GNsxgvfa3wxtaxNLXeS4Vx3qpQVb iRtkMEXkHlUkqWVyPAw95X8WRdZNFYIsi4uTqmb8qrt0USL4zv3YWd6x2 KKf7DyaPhuEBKVahHeYpghRy5lyMUTr8+NfPyEaCO6gTVXrlahWfV5eZg F5s8KLE3OkrzHvbrboDHKBsm8y75neUIZuL68GudpQ4hyKvndaOkNSNUy Q==; IronPort-SDR: cjovsn4rTTduX1BxOOHl/kNOqE3l+rQoKiG6M83lMbT2MYfpw+QdIgV8cSNcVaveKHLNDyAlwm Xft8zEt0kE+mcWQ/D0o9BJ4Y4FWnpx1zGHyhw2SmeTmVFU28ZT87f+T8J+vdAR2pOwaaJOajCp Brv90IdZXju1cLMSrpsouIXIhudSERoUmJpjgIvAu9kqfp7LKMEDWFVk0Gtp/TdO8hr+1Dr0LW KQvowp83Z0rY23k0UWux/G7OaKugkngq9nLuBSvWXVoTSokgaK27WPqDVnPo892p+EWJ4xKRCR 7YM= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="101713940" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:13 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.87.72) by chn-vm-ex02.mchp-main.com (10.10.87.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:13 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:08 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 1/8] dt-bindings: net: dsa: dt bindings for microchip lan937x Date: Thu, 28 Jan 2021 12:11:05 +0530 Message-ID: <20210128064112.372883-2-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Documentation in .yaml format and updates to the MAINTAINERS Also 'make dt_binding_check' is passed Signed-off-by: Prasanna Vengateshan --- .../bindings/net/dsa/microchip,lan937x.yaml | 115 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 116 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml new file mode 100644 index 000000000000..8531ca603f13 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/microchip,lan937x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LAN937x Ethernet Switch Series Tree Bindings + +maintainers: + - woojung.huh@microchip.com + - prasanna.vengateshan@microchip.com + +allOf: + - $ref: dsa.yaml# + +properties: + compatible: + enum: + - microchip,lan9370 + - microchip,lan9371 + - microchip,lan9372 + - microchip,lan9373 + - microchip,lan9374 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 50000000 + + reset-gpios: + description: Optional gpio specifier for a reset line + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + //Ethernet switch connected via spi to the host, CPU port wired to eth1 + eth1 { + #address-cells = <1>; + #size-cells = <0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + spi1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pinctrl_spi_ksz>; + cs-gpios = <0>, <0>, <0>, <&pioC 28 0>; + id = <1>; + + lan9374: switch@0 { + compatible = "microchip,lan9374"; + reg = <0>; + + spi-max-frequency = <44000000>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "lan1"; + }; + port@1 { + reg = <1>; + label = "lan2"; + }; + port@2 { + reg = <7>; + label = "lan3"; + }; + port@3 { + reg = <2>; + label = "lan4"; + }; + port@4 { + reg = <6>; + label = "lan5"; + }; + port@5 { + reg = <3>; + label = "lan6"; + }; + port@6 { + reg = <4>; + label = "cpu"; + ethernet = <ð1>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + port@7 { + reg = <5>; + label = "lan7"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 650deb973913..455670f37231 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11688,6 +11688,7 @@ M: UNGLinuxDriver@microchip.com L: netdev@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +F: Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml F: drivers/net/dsa/microchip/* F: include/linux/platform_data/microchip-ksz.h F: net/dsa/tag_ksz.c From patchwork Thu Jan 28 06:41:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052001 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E7D4C43381 for ; Thu, 28 Jan 2021 06:46:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3E18A64DD9 for ; Thu, 28 Jan 2021 06:46:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231403AbhA1GqE (ORCPT ); Thu, 28 Jan 2021 01:46:04 -0500 Received: from esa.microchip.iphmx.com ([68.232.153.233]:10106 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231347AbhA1Gpo (ORCPT ); Thu, 28 Jan 2021 01:45:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816345; x=1643352345; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9tSKzomBMjhAvNcMzz+sOAdh/RdjsnA65i6SeUfXtFQ=; b=tByXCDfQtpO3O+z/2SAhO+flQrK+U+pdBbR9494Dh+63ZpQM2T1vzPSd XqdqivP7ZVqMSVBqEtmAuv1qDJHMh96nkt/hCM6cG9S85yVWRyeo2Sv8l aToB1MpDVvUpOEsPdTZpkjlskoR0N0ESZ1lvcTWRTSgvbhOIyr8glcjik Vz24qJPwhkBTtzLoaM8WLh2JYUoJLSsFna3GZCfTCKY5+0BP6ztPnk0iC iowHSRhY0kaAzerzHyzmGEH8npuf1zMYFtPvVRGGRSiVnU0dj86gyPCyU pN8zBpYQYVYvOs/vWKudX99lRMTEcmpvaKUiI9NXswhfeLh3b/30xAFI5 Q==; IronPort-SDR: 9RhBQJjcEkVCgDPRlSHzWUUUUXtTHAxnUq2faRy9r0/FVsPvOWyKaFD1XPm+tMy1Mnodx/G/UX Tz+v9BnpWptSptj7RIdKi7ycmvIUaXVzmk4gn2++V6MEts3J+3Bn7s6QymbofIqzm15gvvaFl7 CeDJVIz1PHnlf7+RL9oJ/khGuTj904z+fxcN5mVLH33yznE4N7dtzfkn4a1IrnlR2qY3SH+ZIr r91OfCjnQrrtldnR2Dmfxb6/Q3ugUpNLhip3g7Y4NmuFUVEievKgfL40IDCQOSqJRW5kyuh5/C U4g= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="107076550" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa5.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:20 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:18 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:13 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 2/8] net: dsa: tag_ksz: add tag handling for Microchip LAN937x Date: Thu, 28 Jan 2021 12:11:06 +0530 Message-ID: <20210128064112.372883-3-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org The Microchip LAN937X switches have a tagging protocol which is very similar to KSZ tagging. So that the implementation is added to tag_ksz.c and reused common APIs Signed-off-by: Prasanna Vengateshan --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 4 +-- net/dsa/tag_ksz.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 2f5435d3d1db..b9bc7a9a8c15 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -47,6 +47,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_RTL4_A_VALUE 17 #define DSA_TAG_PROTO_HELLCREEK_VALUE 18 #define DSA_TAG_PROTO_XRS700X_VALUE 19 +#define DSA_TAG_PROTO_LAN937X_VALUE 20 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -69,6 +70,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE, DSA_TAG_PROTO_HELLCREEK = DSA_TAG_PROTO_HELLCREEK_VALUE, DSA_TAG_PROTO_XRS700X = DSA_TAG_PROTO_XRS700X_VALUE, + DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 2d226a5c085f..217fa0f8d13e 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -92,10 +92,10 @@ config NET_DSA_TAG_MTK Mediatek switches. config NET_DSA_TAG_KSZ - tristate "Tag driver for Microchip 8795/9477/9893 families of switches" + tristate "Tag driver for Microchip 8795/9477/9893/937x families of switches" help Say Y if you want to enable support for tagging frames for the - Microchip 8795/9477/9893 families of switches. + Microchip 8795/9477/9893/937x families of switches. config NET_DSA_TAG_RTL4_A tristate "Tag driver for Realtek 4 byte protocol A tags" diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 4820dbcedfa2..6fac39c2b7d5 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -190,10 +190,84 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); +/* For Ingress (Host -> LAN937x), 2 bytes are added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0 : represents tag override, lookup and valid + * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) + * + * For Egress (LAN937x -> Host), 1 byte is added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x07=port8) + */ +#define LAN937X_INGRESS_TAG_LEN 2 + +#define LAN937X_TAIL_TAG_OVERRIDE BIT(11) +#define LAN937X_TAIL_TAG_LOOKUP BIT(12) +#define LAN937X_TAIL_TAG_VALID BIT(13) +#define LAN937X_TAIL_TAG_PORT_MASK 7 + +static struct sk_buff *lan937x_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + __be16 *tag; + u8 *addr; + u16 val; + + /* Tag encoding */ + tag = skb_put(skb, LAN937X_INGRESS_TAG_LEN); + addr = skb_mac_header(skb); + + val = BIT(dp->index); + + if (is_link_local_ether_addr(addr)) + val |= LAN937X_TAIL_TAG_OVERRIDE; + + /* Tail tag valid bit - This bit should always be set by the CPU*/ + val |= LAN937X_TAIL_TAG_VALID; + + *tag = cpu_to_be16(val); + + return skb; +} + +static struct sk_buff *lan937x_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + /* Tag decoding */ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + unsigned int port = tag[0] & LAN937X_TAIL_TAG_PORT_MASK; + unsigned int len = KSZ_EGRESS_TAG_LEN; + + /* Extra 4-bytes PTP timestamp */ + if (tag[0] & KSZ9477_PTP_TAG_INDICATION) + len += KSZ9477_PTP_TAG_LEN; + + return ksz_common_rcv(skb, dev, port, len); +} + +static const struct dsa_device_ops lan937x_netdev_ops = { + .name = "lan937x", + .proto = DSA_TAG_PROTO_LAN937X, + .xmit = lan937x_xmit, + .rcv = lan937x_rcv, + .overhead = LAN937X_INGRESS_TAG_LEN, + .tail_tag = true, +}; + +DSA_TAG_DRIVER(lan937x_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X); + static struct dsa_tag_driver *dsa_tag_driver_array[] = { &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), + &DSA_TAG_DRIVER_NAME(lan937x_netdev_ops), }; module_dsa_tag_drivers(dsa_tag_driver_array); From patchwork Thu Jan 28 06:41:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052013 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59BE3C433E6 for ; Thu, 28 Jan 2021 06:47:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F363C64DCE for ; Thu, 28 Jan 2021 06:47:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231520AbhA1GrR (ORCPT ); Thu, 28 Jan 2021 01:47:17 -0500 Received: from esa.microchip.iphmx.com ([68.232.153.233]:10106 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231422AbhA1GqO (ORCPT ); Thu, 28 Jan 2021 01:46:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816373; x=1643352373; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BKzC+n/i9bsNW7jW/bhc7j7ObDFEQYi60fijuAISd84=; b=ZZuFimR7xVBUnGXc5KBOa7zM94oQUhoBEGX+N1+NzP4BDNyf8AaFsrtJ X0FmGpL+BBJb4fNd2YX34oPqTvKQ/HOF+kToS2EazLNXFZFBAhzSVRtza OYKfHE/dYNI4/q18hgq4rAy8H32up7g4rV/BNETLh/56Eb7kojew8M9ID 3NqzFFmbsgHc06FHJPvHZsKyr8iGRJQZYiyBU6YeB7MJCgQSrFluxcX3T eftc6kIIx8gVlP2bY0nZ0FP4m04eRTV+qpDEtDw9bLp25jT6g9B1n9xPE fFwX5DgB3KioOOTBvBVxcsdfl24xdcfs3p1X3iB7cNDv/nQUbYwZDldVh w==; IronPort-SDR: tgBvDswc6HpZATPFtabZ3/2YrwbnH8H3dHotUBTIATgUsFs0UsUcSTeISxKVrkrkIT4+AD0QXz CjoB4CskDXhvQ9mUKMGEHxKk82nQPQUZnFn7Phrz6fERzTji49GE6D8z34EWTOUs24pMbMqNKh Cxr5ZalPuykVzB3+f6b4ZcXwZ9fLLE8sDwcuw4uOrFcleeAZMMl/CG7cbg4IJSI4BdLan7IyNb iEnEFZgSO3visB82P2K3szegUaMrFVQfyI29Kxw4ufaxn10FQWMAKCKPUVIDenvL/dKw/qmX+8 Je4= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="107076573" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa5.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:27 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:24 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:19 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 3/8] net: dsa: microchip: add DSA support for microchip lan937x Date: Thu, 28 Jan 2021 12:11:07 +0530 Message-ID: <20210128064112.372883-4-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Basic DSA driver support for lan937x and the device will be configured through SPI interface. drivers/net/dsa/microchip/ path is already part of MAINTAINERS & the new files come under this path. Hence no update needed to the MAINTAINERS Reused KSZ APIs for port_bridge_join() & port_bridge_leave() and added support for port_stp_state_set() & port_fast_age(). lan937x_flush_dyn_mac_table() which gets called from port_fast_age() of KSZ common layer, hence added support for it. Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/Kconfig | 12 + drivers/net/dsa/microchip/Makefile | 5 + drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/dsa/microchip/lan937x_dev.c | 859 ++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 79 ++ drivers/net/dsa/microchip/lan937x_main.c | 352 +++++++++ drivers/net/dsa/microchip/lan937x_reg.h | 955 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_spi.c | 104 +++ 8 files changed, 2367 insertions(+) create mode 100644 drivers/net/dsa/microchip/lan937x_dev.c create mode 100644 drivers/net/dsa/microchip/lan937x_dev.h create mode 100644 drivers/net/dsa/microchip/lan937x_main.c create mode 100644 drivers/net/dsa/microchip/lan937x_reg.h create mode 100644 drivers/net/dsa/microchip/lan937x_spi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 4ec6a47b7f72..ae2484e3759b 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -3,6 +3,18 @@ config NET_DSA_MICROCHIP_KSZ_COMMON select NET_DSA_TAG_KSZ tristate +config NET_DSA_MICROCHIP_LAN937X + tristate "Microchip LAN937X series SPI connected switch support" + depends on NET_DSA && SPI + select NET_DSA_MICROCHIP_KSZ_COMMON + select REGMAP_SPI + help + This driver adds support for Microchip LAN937X series + switch chips. + + Select to enable support for registering switches configured + through SPI. + menuconfig NET_DSA_MICROCHIP_KSZ9477 tristate "Microchip KSZ9477 series switch support" depends on NET_DSA diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 929caa81e782..13f38efdadf0 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -5,3 +5,8 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI) += ksz9477_spi.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795) += ksz8795.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI) += ksz8795_spi.o + +obj-$(CONFIG_NET_DSA_MICROCHIP_LAN937X) += lan937x.o +lan937x-objs := lan937x_dev.o +lan937x-objs += lan937x_main.o +lan937x-objs += lan937x_spi.o diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index f212775372ce..7cc14b72ad39 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -144,6 +144,7 @@ void ksz_switch_remove(struct ksz_device *dev); int ksz8795_switch_register(struct ksz_device *dev); int ksz9477_switch_register(struct ksz_device *dev); +int lan937x_switch_register(struct ksz_device *dev); void ksz_update_port_member(struct ksz_device *dev, int port); void ksz_init_mib_timer(struct ksz_device *dev); diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c new file mode 100644 index 000000000000..84540180ff2f --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -0,0 +1,859 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip lan937x dev ops functions + * Copyright (C) 2019-2020 Microchip Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lan937x_reg.h" +#include "ksz_common.h" +#include "lan937x_dev.h" + +const struct mib_names lan937x_mib_names[] = { + { 0x00, "rx_hi" }, + { 0x01, "rx_undersize" }, + { 0x02, "rx_fragments" }, + { 0x03, "rx_oversize" }, + { 0x04, "rx_jabbers" }, + { 0x05, "rx_symbol_err" }, + { 0x06, "rx_crc_err" }, + { 0x07, "rx_align_err" }, + { 0x08, "rx_mac_ctrl" }, + { 0x09, "rx_pause" }, + { 0x0A, "rx_bcast" }, + { 0x0B, "rx_mcast" }, + { 0x0C, "rx_ucast" }, + { 0x0D, "rx_64_or_less" }, + { 0x0E, "rx_65_127" }, + { 0x0F, "rx_128_255" }, + { 0x10, "rx_256_511" }, + { 0x11, "rx_512_1023" }, + { 0x12, "rx_1024_1522" }, + { 0x13, "rx_1523_2000" }, + { 0x14, "rx_2001" }, + { 0x15, "tx_hi" }, + { 0x16, "tx_late_col" }, + { 0x17, "tx_pause" }, + { 0x18, "tx_bcast" }, + { 0x19, "tx_mcast" }, + { 0x1A, "tx_ucast" }, + { 0x1B, "tx_deferred" }, + { 0x1C, "tx_total_col" }, + { 0x1D, "tx_exc_col" }, + { 0x1E, "tx_single_col" }, + { 0x1F, "tx_mult_col" }, + { 0x80, "rx_total" }, + { 0x81, "tx_total" }, + { 0x82, "rx_discards" }, + { 0x83, "tx_discards" }, +}; + +static const struct lan937x_chip_data lan937x_switch_chips[] = { + { + .chip_id = 0x00937000, + .dev_name = "LAN9370", + .num_vlans = 4096, + .num_alus = 1024, + .num_statics = 256, + /* can be configured as cpu port */ + .cpu_ports = 0x10, + /* total port count */ + .port_cnt = 5, + }, + { + .chip_id = 0x00937100, + .dev_name = "LAN9371", + .num_vlans = 4096, + .num_alus = 1024, + .num_statics = 256, + /* can be configured as cpu port */ + .cpu_ports = 0x30, + /* total port count */ + .port_cnt = 6, + }, + { + .chip_id = 0x00937200, + .dev_name = "LAN9372", + .num_vlans = 4096, + .num_alus = 1024, + .num_statics = 256, + /* can be configured as cpu port */ + .cpu_ports = 0x30, + /* total port count */ + .port_cnt = 8, + }, + { + .chip_id = 0x00937300, + .dev_name = "LAN9373", + .num_vlans = 4096, + .num_alus = 1024, + .num_statics = 256, + /* can be configured as cpu port */ + .cpu_ports = 0x38, + /* total port count */ + .port_cnt = 5, + }, + { + .chip_id = 0x00937400, + .dev_name = "LAN9374", + .num_vlans = 4096, + .num_alus = 1024, + .num_statics = 256, + /* can be configured as cpu port */ + .cpu_ports = 0x30, + /* total port count */ + .port_cnt = 8, + }, + +}; + +void lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +void lan937x_port_cfg(struct ksz_device *dev, int port, int offset, + u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); +} + +void lan937x_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) +{ + regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); +} + +void lan937x_pread8(struct ksz_device *dev, int port, int offset, + u8 *data) +{ + ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_pread16(struct ksz_device *dev, int port, int offset, + u16 *data) +{ + ksz_read16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_pread32(struct ksz_device *dev, int port, int offset, + u32 *data) +{ + ksz_read32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_pwrite8(struct ksz_device *dev, int port, + int offset, u8 data) +{ + ksz_write8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_pwrite16(struct ksz_device *dev, int port, + int offset, u16 data) +{ + ksz_write16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_pwrite32(struct ksz_device *dev, int port, + int offset, u32 data) +{ + ksz_write32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_port_cfg32(struct ksz_device *dev, int port, int offset, + u32 bits, bool set) +{ + regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); +} + +void lan937x_cfg_port_member(struct ksz_device *dev, int port, + u8 member) +{ + lan937x_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); + + dev->ports[port].member = member; +} + +static void lan937x_flush_dyn_mac_table(struct ksz_device *dev, int port) +{ + unsigned int value; + u8 data; + + regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2, + SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S, + SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); + + if (port < dev->port_cnt) { + /* flush individual port */ + lan937x_pread8(dev, port, P_STP_CTRL, &data); + if (!(data & PORT_LEARN_DISABLE)) + lan937x_pwrite8(dev, port, P_STP_CTRL, + data | PORT_LEARN_DISABLE); + lan937x_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true); + + regmap_read_poll_timeout(dev->regmap[0], + S_FLUSH_TABLE_CTRL, + value, !(value & SW_FLUSH_DYN_MAC_TABLE), 10, 1000); + + lan937x_pwrite8(dev, port, P_STP_CTRL, data); + } else { + /* flush all */ + lan937x_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true); + } +} + +static void lan937x_port_init_cnt(struct ksz_device *dev, int port) +{ + struct ksz_port_mib *mib = &dev->ports[port].mib; + + /* flush all enabled port MIB counters */ + mutex_lock(&mib->cnt_mutex); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, + MIB_COUNTER_FLUSH_FREEZE); + ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0); + mutex_unlock(&mib->cnt_mutex); + + mib->cnt_ptr = 0; + memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); +} + +int lan937x_reset_switch(struct ksz_device *dev) +{ + u32 data32; + u8 data8; + + /* reset switch */ + lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true); + + /* default configuration */ + ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING | + SW_SRC_ADDR_FILTER; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); + + /* disable interrupts */ + ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); + ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF); + ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); + + /* set broadcast storm protection 10% rate */ + regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2, + BROADCAST_STORM_RATE, + (BROADCAST_STORM_VALUE * + BROADCAST_STORM_PROT_RATE) / 100); + + return 0; +} + +static int lan937x_switch_detect(struct ksz_device *dev) +{ + u32 id32; + int ret; + + /* Read Chip ID */ + ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32); + + if (ret) + return ret; + + if (id32 != 0) { + dev->chip_id = id32; + dev_info(dev->dev, "Chip ID: 0x%x", id32); + ret = 0; + } else { + ret = -EINVAL; + } + return ret; +} + +static void lan937x_switch_exit(struct ksz_device *dev) +{ + lan937x_reset_switch(dev); +} + +void lan937x_enable_spi_indirect_access(struct ksz_device *dev) +{ + u16 data16; + u8 data8; + + ksz_read8(dev, REG_GLOBAL_CTRL_0, &data8); + + /* Check if PHY register is blocked */ + if (data8 & SW_PHY_REG_BLOCK) { + /* Enable Phy access through SPI*/ + data8 &= ~SW_PHY_REG_BLOCK; + ksz_write8(dev, REG_GLOBAL_CTRL_0, data8); + } + + ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16); + + /* If already the access is not enabled go ahead and allow SPI access */ + if (!(data16 & VPHY_SPI_INDIRECT_ENABLE)) { + data16 |= VPHY_SPI_INDIRECT_ENABLE; + ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16); + } +} + +bool lan937x_is_internal_phy_port(struct ksz_device *dev, int port) +{ + /* Check if the port is RGMII */ + if (port == LAN937X_RGMII_1_PORT || port == LAN937X_RGMII_2_PORT) + return false; + + /* Check if the port is SGMII */ + if (port == LAN937X_SGMII_PORT && + GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_73) + return false; + + return true; +} + +static u32 lan937x_get_port_addr(int port, int offset) +{ + return PORT_CTRL_ADDR(port, offset); +} + +bool lan937x_is_internal_tx_phy_port(struct ksz_device *dev, int port) +{ + /* Check if the port is internal tx phy port */ + if (lan937x_is_internal_phy_port(dev, port) && port == LAN937X_TXPHY_PORT) + if ((GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_71) || + (GET_CHIP_ID_LSB(dev->chip_id) == CHIP_ID_72)) + return true; + + return false; +} + +bool lan937x_is_internal_t1_phy_port(struct ksz_device *dev, int port) +{ + /* Check if the port is internal t1 phy port */ + if (lan937x_is_internal_phy_port(dev, port) && + !lan937x_is_internal_tx_phy_port(dev, port)) + return true; + + return false; +} + +int lan937x_t1_tx_phy_write(struct ksz_device *dev, int addr, + int reg, u16 val) +{ + u16 temp, addr_base; + unsigned int value; + int ret; + + /* Check for internal phy port */ + if (!lan937x_is_internal_phy_port(dev, addr)) + return 0; + + if (lan937x_is_internal_tx_phy_port(dev, addr)) + addr_base = REG_PORT_TX_PHY_CTRL_BASE; + else + addr_base = REG_PORT_T1_PHY_CTRL_BASE; + + temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2))); + + ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp); + + /* Write the data to be written to the VPHY reg */ + ksz_write16(dev, REG_VPHY_IND_DATA__2, val); + + /* Write the Write En and Busy bit */ + ksz_write16(dev, REG_VPHY_IND_CTRL__2, (VPHY_IND_WRITE + | VPHY_IND_BUSY)); + + ret = regmap_read_poll_timeout(dev->regmap[1], + REG_VPHY_IND_CTRL__2, + value, !(value & VPHY_IND_BUSY), 10, 1000); + + /* failed to write phy register. get out of loop */ + if (ret) { + dev_err(dev->dev, "Failed to write phy register\n"); + return ret; + } + + return 0; +} + +int lan937x_t1_tx_phy_read(struct ksz_device *dev, int addr, + int reg, u16 *val) +{ + u16 temp, addr_base; + unsigned int value; + int ret; + + if (lan937x_is_internal_phy_port(dev, addr)) { + if (lan937x_is_internal_tx_phy_port(dev, addr)) + addr_base = REG_PORT_TX_PHY_CTRL_BASE; + else + addr_base = REG_PORT_T1_PHY_CTRL_BASE; + + /* get register address based on the logical port */ + temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2))); + + ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp); + /* Write Read and Busy bit to start the transaction*/ + ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY); + + ret = regmap_read_poll_timeout(dev->regmap[1], + REG_VPHY_IND_CTRL__2, + value, !(value & VPHY_IND_BUSY), 10, 1000); + + /* failed to read phy register. get out of loop */ + if (ret) { + dev_err(dev->dev, "Failed to read phy register\n"); + return ret; + } + /* Read the VPHY register which has the PHY data*/ + ksz_read16(dev, REG_VPHY_IND_DATA__2, val); + } + + return 0; +} + +static void lan937x_t1_tx_phy_mod_bits(struct ksz_device *dev, int port, + int reg, u16 val, bool set) +{ + u16 data; + + /* read phy register */ + lan937x_t1_tx_phy_read(dev, port, reg, &data); + + /* set/clear the data */ + if (set) + data |= val; + else + data &= ~val; + + /* write phy register */ + lan937x_t1_tx_phy_write(dev, port, reg, data); +} + +static u32 lan937x_tx_phy_bank_read(struct ksz_device *dev, int port, + u8 bank, u8 reg) +{ + u16 data_hi; + u16 data_lo; + u16 ctrl; + + ctrl = ((u16)bank & TX_REG_BANK_SEL_M) << TX_REG_BANK_SEL_S; + ctrl |= ((u16)reg & TX_READ_ADDR_M) << TX_READ_ADDR_S; + + /* write ctrl register with appropriate value */ + ctrl |= TX_IND_DATA_READ; + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl); + + /* if bank is WOL value to be written again to reflect correct bank */ + if (bank == TX_REG_BANK_SEL_WOL) + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl); + + /* read data hi & low value */ + lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_READ_DATA_LO, &data_lo); + lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_READ_DATA_HI, &data_hi); + + return ((u32)data_hi << 16) | data_lo; +} + +static void lan937x_tx_phy_bank_write(struct ksz_device *dev, int port, + u8 bank, u8 reg, u16 val) +{ + u16 ctrl; + + /* write the value */ + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_WRITE_DATA, val); + ctrl = ((u16)bank & TX_REG_BANK_SEL_M) << TX_REG_BANK_SEL_S; + ctrl |= (reg & TX_WRITE_ADDR_M); + + if (bank == TX_REG_BANK_SEL_DSP || bank == TX_REG_BANK_SEL_BIST) + ctrl |= TX_TEST_MODE; + /* write ctrl register with write operation bit set */ + ctrl |= TX_IND_DATA_WRITE; + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, ctrl); +} + +static void tx_phy_setup(struct ksz_device *dev, int port) +{ + u16 data_lo; + + lan937x_t1_tx_phy_read(dev, port, REG_PORT_TX_SPECIAL_MODES, &data_lo); + /* Need to change configuration from 6 to other value. */ + data_lo &= TX_PHYADDR_M; + + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_SPECIAL_MODES, data_lo); + + /* Need to toggle test_mode bit to enable DSP access. */ + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, TX_TEST_MODE); + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, 0); + + /* Note TX_TEST_MODE is then always enabled so this is not required. */ + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, TX_TEST_MODE); + lan937x_t1_tx_phy_write(dev, port, REG_PORT_TX_IND_CTRL, 0); +} + +static void tx_phy_port_init(struct ksz_device *dev, int port) +{ + u32 data; + + /* Software reset. */ + lan937x_t1_tx_phy_mod_bits(dev, port, MII_BMCR, BMCR_RESET, true); + + /* tx phy setup */ + tx_phy_setup(dev, port); + + /* tx phy init sequence */ + data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_VMDAC, + TX_VMDAC_ZQ_CAL_CTRL); + data |= TX_START_ZQ_CAL; + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, + TX_VMDAC_ZQ_CAL_CTRL, data); + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, TX_VMDAC_CTRL0, + TX_VMDAC_CTRL0_VAL); + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, TX_VMDAC_CTRL1, + TX_VMDAC_CTRL1_VAL); + data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_VMDAC, + TX_VMDAC_MISC_PCS_CTRL0); + data |= TX_MISC_PCS_CTRL0_13; + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, + TX_VMDAC_MISC_PCS_CTRL0, data); + + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, TX_DSP_DCBLW, + TX_DSP_DCBLW_VAL); + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, TX_DSP_A11_CONFIG, + TX_DSP_A11_CONFIG_VAL); + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_DSP, TX_DSP_A10_CONFIG, + TX_DSP_A10_CONFIG_VAL); + data = lan937x_tx_phy_bank_read(dev, port, TX_REG_BANK_SEL_DSP, + TX_DSP_A5_CONFIG); + data &= ~(TX_A5_TXCLKPHSEL_M << TX_A5_TXCLKPHSEL_S); + data |= (TX_A5_TXCLK_2_NS << TX_A5_TXCLKPHSEL_S); + lan937x_tx_phy_bank_write(dev, port, TX_REG_BANK_SEL_VMDAC, + TX_DSP_A5_CONFIG, data); +} + +static void lan937x_t1_phy_bank_sel(struct ksz_device *dev, int port, + u8 bank, u8 addr, u16 oper) +{ + u16 data, ctrl; + u8 prev_bank; + + lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_EXT_REG_CTRL, &ctrl); + prev_bank = (ctrl >> T1_REG_BANK_SEL_S) & T1_REG_BANK_SEL_M; + ctrl &= T1_PCS_STS_CNT_RESET; + + data = ((u16)bank & T1_REG_BANK_SEL_M) << T1_REG_BANK_SEL_S; + data |= (addr & T1_REG_ADDR_M); + data |= oper; + data |= ctrl; + + /* if the bank is DSP need to write twice */ + if (bank != prev_bank && bank == T1_REG_BANK_SEL_DSP) { + u16 t = data & ~T1_REG_ADDR_M; + + t &= ~oper; + t |= T1_IND_DATA_READ; + + /* Need to write twice to access correct register. */ + lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_CTRL, t); + } + + lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_CTRL, data); +} + +static void lan937x_t1_phy_bank_read(struct ksz_device *dev, int port, + u8 bank, u8 addr, u16 *val) +{ + /* select the bank for read operation */ + lan937x_t1_phy_bank_sel(dev, port, bank, addr, T1_IND_DATA_READ); + + /* read bank */ + lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_EXT_REG_RD_DATA, val); +} + +static void lan937x_t1_phy_bank_write(struct ksz_device *dev, int port, + u8 bank, u8 addr, u16 val) +{ + /* write the data to be written into the bank */ + lan937x_t1_tx_phy_write(dev, port, REG_PORT_T1_EXT_REG_WR_DATA, val); + /* select the bank for write operation */ + lan937x_t1_phy_bank_sel(dev, port, bank, addr, T1_IND_DATA_WRITE); +} + +static void t1_phy_port_init(struct ksz_device *dev, int port) +{ + u16 val; + + /* Power down the PHY. */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL, + PORT_T1_POWER_DOWN, true); + + /* Make sure software initialization sequence is used. */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_POWER_DOWN_CTRL, + T1_HW_INIT_SEQ_ENABLE, false); + + /* Configure T1 phy role */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_M_CTRL, + PORT_T1_M_CFG, true); + + /* Software reset. */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL, + PORT_T1_PHY_RESET, true); + + /* cdr mode */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x34, 0x0001); + + /* setting lock 3 mufac */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x1B, 0x0B6A); + + /* setting pos lock mufac */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x1C, 0x0B6B); + + /* setting lock1 win config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x11, 0x2A74); + + /* setting lock2 win config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x12, 0x2B70); + + /* setting lock3 win config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x13, 0x2B6C); + + /* setting plock */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x14, 0x2974); + + /* setting lock threshold config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x16, 0xC803); + + /* slv fd stg bmp */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x24, 0x0002); + + /* Blw BW config lock stage 3 */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x2A, 0x003C); + + /* Blw BW config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x56, 0x3CAA); + + /* Blw BW config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x57, 0x1E47); + + /* Blw BW config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x58, 0x1E4E); + + /* Blw BW config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x59, 0x1E56); + + /* disable scrambler lock timeout 0-disable 1- enable */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x32, 0x00F6); + + /* reducing energy detect partial timeout */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x3C, 0x64CC); + + lan937x_t1_tx_phy_read(dev, port, 0x0A, &val); + + if ((val & 0x4000) == 0) + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x26, 0x1770); + + /* pwr dn Config */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x04, 0x16D7); + + /* scrambler lock hysterisis */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x00, 0x7FFF); + + /* eq status timer control */ + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_PCS, 0x02, 0x07FF); + + /* MANUAL STD POLARITY */ + lan937x_t1_tx_phy_write(dev, port, 0x17, 0x0080); + + /* disable master mode energy detect */ + lan937x_t1_tx_phy_mod_bits(dev, port, 0x10, 0x0040, false); + + lan937x_t1_phy_bank_read(dev, port, T1_REG_BANK_SEL_AFE, 0x0B, &val); + + val &= ~0x001E; + /* increase tx amp to 0b0101 */ + val |= 0x000A; + + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_AFE, 0x0B, val); + + lan937x_t1_phy_bank_write(dev, port, T1_REG_BANK_SEL_DSP, 0x25, 0x23E0); + + /* Set HW_INIT */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_POWER_DOWN_CTRL, + T1_HW_INIT_SEQ_ENABLE, true); + + /* Power up the PHY. */ + lan937x_t1_tx_phy_mod_bits(dev, port, REG_PORT_T1_PHY_BASIC_CTRL, + PORT_T1_POWER_DOWN, false); +} + +static void lan937x_set_gbit(struct ksz_device *dev, bool gbit, u8 *data) +{ + if (gbit) + *data &= ~PORT_MII_NOT_1GBIT; + else + *data |= PORT_MII_NOT_1GBIT; +} + +void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) +{ + struct ksz_port *p = &dev->ports[port]; + u8 data8, member; + + /* enable tag tail for host port */ + if (cpu_port) { + lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE, + true); + /* Enable jumbo packet in host port so that frames are not + * counted as oversized. + */ + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_JUMBO_PACKET, + true); + lan937x_pwrite16(dev, port, REG_PORT_MTU__2, FR_SIZE_CPU_PORT); + } + + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_FR_CHK_LENGTH, + false); + + lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false); + + /* set back pressure */ + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true); + + /* enable broadcast storm limit */ + lan937x_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); + + /* disable DiffServ priority */ + lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false); + + /* replace priority */ + lan937x_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING, + false); + lan937x_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4, + MTI_PVID_REPLACE, false); + + /* enable 802.1p priority */ + lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); + + /* phy init for internal ports */ + if (lan937x_is_internal_phy_port(dev, port)) { + if (lan937x_is_internal_tx_phy_port(dev, port)) + tx_phy_port_init(dev, port); + else + t1_phy_port_init(dev, port); + + } else { + /* force flow control off*/ + lan937x_port_cfg(dev, port, REG_PORT_XMII_CTRL_0, + PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, + false); + + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); + + /* clear MII selection & set it based on interface later */ + data8 &= ~PORT_MII_SEL_M; + + /* configure MAC based on p->interface */ + switch (p->interface) { + case PHY_INTERFACE_MODE_MII: + lan937x_set_gbit(dev, false, &data8); + data8 |= PORT_MII_SEL; + break; + case PHY_INTERFACE_MODE_RMII: + lan937x_set_gbit(dev, false, &data8); + data8 |= PORT_RMII_SEL; + break; + default: + lan937x_set_gbit(dev, true, &data8); + data8 |= PORT_RGMII_SEL; + + data8 &= ~PORT_RGMII_ID_IG_ENABLE; + data8 &= ~PORT_RGMII_ID_EG_ENABLE; + + if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || + p->interface == PHY_INTERFACE_MODE_RGMII_RXID) + data8 |= PORT_RGMII_ID_IG_ENABLE; + + if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || + p->interface == PHY_INTERFACE_MODE_RGMII_TXID) + data8 |= PORT_RGMII_ID_EG_ENABLE; + break; + } + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); + } + + if (cpu_port) + member = dev->port_mask; + else + member = dev->host_mask | p->vid_member; + + lan937x_cfg_port_member(dev, port, member); +} + +static int lan937x_switch_init(struct ksz_device *dev) +{ + int i; + + dev->ds->ops = &lan937x_switch_ops; + + for (i = 0; i < ARRAY_SIZE(lan937x_switch_chips); i++) { + const struct lan937x_chip_data *chip = &lan937x_switch_chips[i]; + + if (dev->chip_id == chip->chip_id) { + dev->name = chip->dev_name; + dev->num_vlans = chip->num_vlans; + dev->num_alus = chip->num_alus; + dev->num_statics = chip->num_statics; + dev->port_cnt = chip->port_cnt; + dev->cpu_ports = chip->cpu_ports; + break; + } + } + + /* no switch found */ + if (!dev->port_cnt) + return -ENODEV; + + dev->port_mask = (1 << dev->port_cnt) - 1; + + dev->reg_mib_cnt = SWITCH_COUNTER_NUM; + dev->mib_cnt = ARRAY_SIZE(lan937x_mib_names); + + dev->ports = devm_kzalloc(dev->dev, + dev->port_cnt * sizeof(struct ksz_port), + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + + for (i = 0; i < dev->port_cnt; i++) { + mutex_init(&dev->ports[i].mib.cnt_mutex); + dev->ports[i].mib.counters = + devm_kzalloc(dev->dev, + sizeof(u64) * + (dev->mib_cnt + 1), + GFP_KERNEL); + if (!dev->ports[i].mib.counters) + return -ENOMEM; + } + + /* set the real number of ports */ + dev->ds->num_ports = dev->port_cnt; + return 0; +} + +const struct ksz_dev_ops lan937x_dev_ops = { + .get_port_addr = lan937x_get_port_addr, + .cfg_port_member = lan937x_cfg_port_member, + .flush_dyn_mac_table = lan937x_flush_dyn_mac_table, + .port_setup = lan937x_port_setup, + .port_init_cnt = lan937x_port_init_cnt, + .shutdown = lan937x_reset_switch, + .detect = lan937x_switch_detect, + .init = lan937x_switch_init, + .exit = lan937x_switch_exit, +}; diff --git a/drivers/net/dsa/microchip/lan937x_dev.h b/drivers/net/dsa/microchip/lan937x_dev.h new file mode 100644 index 000000000000..e78483793642 --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip lan937x dev ops headers + * Copyright (C) 2019-2020 Microchip Technology Inc. + */ + +#ifndef __LAN937X_CFG_H +#define __LAN937X_CFG_H + +void lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set); +void lan937x_port_cfg(struct ksz_device *dev, int port, int offset, + u8 bits, bool set); +void lan937x_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set); +void lan937x_pread8(struct ksz_device *dev, int port, int offset, + u8 *data); +void lan937x_pread16(struct ksz_device *dev, int port, int offset, + u16 *data); +void lan937x_pread32(struct ksz_device *dev, int port, int offset, + u32 *data); +void lan937x_pwrite8(struct ksz_device *dev, int port, + int offset, u8 data); +void lan937x_pwrite16(struct ksz_device *dev, int port, + int offset, u16 data); +void lan937x_pwrite32(struct ksz_device *dev, int port, + int offset, u32 data); +void lan937x_port_cfg32(struct ksz_device *dev, int port, int offset, + u32 bits, bool set); +int lan937x_t1_tx_phy_write(struct ksz_device *dev, int addr, + int reg, u16 val); +int lan937x_t1_tx_phy_read(struct ksz_device *dev, int addr, + int reg, u16 *val); +bool lan937x_is_internal_tx_phy_port(struct ksz_device *dev, int port); +bool lan937x_is_internal_t1_phy_port(struct ksz_device *dev, int port); +bool lan937x_is_internal_phy_port(struct ksz_device *dev, int port); +int lan937x_reset_switch(struct ksz_device *dev); +void lan937x_cfg_port_member(struct ksz_device *dev, int port, + u8 member); +void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); +int lan937x_sw_register(struct ksz_device *dev); +void lan937x_enable_spi_indirect_access(struct ksz_device *dev); + +struct mib_names { + int index; + char string[ETH_GSTRING_LEN]; +}; + +struct lan937x_chip_data { + u32 chip_id; + const char *dev_name; + int num_vlans; + int num_alus; + int num_statics; + int cpu_ports; + int port_cnt; +}; + +struct lan_alu_struct { + /* entry 1 */ + u8 is_static:1; + u8 is_src_filter:1; + u8 is_dst_filter:1; + u8 prio_age:3; + u32 _reserv_0_1:23; + u8 mstp:3; + /* entry 2 */ + u8 is_override:1; + u8 is_use_fid:1; + u32 _reserv_1_1:22; + u8 port_forward:8; + /* entry 3 & 4*/ + u32 _reserv_2_1:9; + u8 fid:7; + u8 mac[ETH_ALEN]; +}; + +extern const struct dsa_switch_ops lan937x_switch_ops; +extern const struct ksz_dev_ops lan937x_dev_ops; +extern const struct mib_names lan937x_mib_names[]; + +#endif diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c new file mode 100644 index 000000000000..41f7f5f8f435 --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip LAN937X switch driver main logic + * Copyright (C) 2019-2020 Microchip Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "lan937x_reg.h" +#include "ksz_common.h" +#include "lan937x_dev.h" + +static enum dsa_tag_protocol lan937x_get_tag_protocol(struct dsa_switch *ds, + int port, + enum dsa_tag_protocol mp) +{ + return DSA_TAG_PROTO_LAN937X_VALUE; +} + +static int lan937x_get_link_status(struct ksz_device *dev, int port) +{ + u16 val1, val2; + + lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_PHY_M_STATUS, + &val1); + + lan937x_t1_tx_phy_read(dev, port, REG_PORT_T1_MODE_STAT, &val2); + + if (val1 & (PORT_T1_LOCAL_RX_OK | PORT_T1_REMOTE_RX_OK) && + val2 & (T1_PORT_DSCR_LOCK_STATUS_MSK | T1_PORT_LINK_UP_MSK)) + return PHY_LINK_UP; + + return PHY_LINK_DOWN; +} + +static int lan937x_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val; + + lan937x_t1_tx_phy_read(dev, addr, reg, &val); + + if (reg == MII_BMSR && lan937x_is_internal_t1_phy_port(dev, addr)) { + /* T1 PHY supports only 100 Mb FD, report through BMSR_100FULL bit*/ + val |= BMSR_100FULL; + + /* T1 Phy link is based on REG_PORT_T1_PHY_M_STATUS & REG_PORT_T1 + * _MODE_STAT registers for LAN937x, get the link status + * and report through BMSR_LSTATUS bit + */ + if (lan937x_get_link_status(dev, addr) == PHY_LINK_UP) + val |= BMSR_LSTATUS; + else + val &= ~BMSR_LSTATUS; + } + + return val; +} + +static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg, + u16 val) +{ + struct ksz_device *dev = ds->priv; + + return lan937x_t1_tx_phy_write(dev, addr, reg, val); +} + +static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, + u8 state) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *p = &dev->ports[port]; + int forward = dev->member; + int member = -1; + u8 data; + + lan937x_pread8(dev, port, P_STP_CTRL, &data); + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); + + switch (state) { + case BR_STATE_DISABLED: + data |= PORT_LEARN_DISABLE; + if (port != dev->cpu_port) + member = 0; + break; + case BR_STATE_LISTENING: + data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); + if (port != dev->cpu_port && + p->stp_state == BR_STATE_DISABLED) + member = dev->host_mask | p->vid_member; + break; + case BR_STATE_LEARNING: + data |= PORT_RX_ENABLE; + break; + case BR_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + + /* This function is also used internally. */ + if (port == dev->cpu_port) + break; + + member = dev->host_mask | p->vid_member; + mutex_lock(&dev->dev_mutex); + + /* Port is a member of a bridge. */ + if (dev->br_member & (1 << port)) { + dev->member |= (1 << port); + member = dev->member; + } + mutex_unlock(&dev->dev_mutex); + break; + case BR_STATE_BLOCKING: + data |= PORT_LEARN_DISABLE; + if (port != dev->cpu_port && + p->stp_state == BR_STATE_DISABLED) + member = dev->host_mask | p->vid_member; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + lan937x_pwrite8(dev, port, P_STP_CTRL, data); + + p->stp_state = state; + mutex_lock(&dev->dev_mutex); + + /* Port membership may share register with STP state. */ + if (member >= 0 && member != p->member) + lan937x_cfg_port_member(dev, port, (u8)member); + + /* Check if forwarding needs to be updated. */ + if (state != BR_STATE_FORWARDING) { + if (dev->br_member & (1 << port)) + dev->member &= ~(1 << port); + } + + /* When topology has changed the function ksz_update_port_member + * should be called to modify port forwarding behavior. + */ + if (forward != dev->member) + ksz_update_port_member(dev, port); + mutex_unlock(&dev->dev_mutex); +} + +static phy_interface_t lan937x_get_interface(struct ksz_device *dev, int port) +{ + phy_interface_t interface; + u8 data8; + + if (lan937x_is_internal_phy_port(dev, port)) + return PHY_INTERFACE_MODE_NA; + + /* read interface from REG_PORT_XMII_CTRL_1 register */ + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); + + switch (data8 & PORT_MII_SEL_M) { + case PORT_RMII_SEL: + interface = PHY_INTERFACE_MODE_RMII; + break; + case PORT_RGMII_SEL: + interface = PHY_INTERFACE_MODE_RGMII; + if (data8 & PORT_RGMII_ID_EG_ENABLE) + interface = PHY_INTERFACE_MODE_RGMII_TXID; + if (data8 & PORT_RGMII_ID_IG_ENABLE) { + interface = PHY_INTERFACE_MODE_RGMII_RXID; + if (data8 & PORT_RGMII_ID_EG_ENABLE) + interface = PHY_INTERFACE_MODE_RGMII_ID; + } + break; + case PORT_MII_SEL: + default: + /* Interface is MII */ + interface = PHY_INTERFACE_MODE_MII; + break; + } + return interface; +} + +static void lan937x_config_cpu_port(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *p; + int i; + + ds->num_ports = dev->port_cnt; + + for (i = 0; i < dev->port_cnt; i++) { + if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) { + phy_interface_t interface; + const char *prev_msg; + const char *prev_mode; + + dev->cpu_port = i; + dev->host_mask = (1 << dev->cpu_port); + dev->port_mask |= dev->host_mask; + p = &dev->ports[i]; + + /* Read from XMII register to determine host port + * interface. If set specifically in device tree + * note the difference to help debugging. + */ + interface = lan937x_get_interface(dev, i); + if (!p->interface) { + if (dev->compat_interface) { + dev_warn(dev->dev, + "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. Please update your device tree.\n", + i); + p->interface = dev->compat_interface; + } else { + p->interface = interface; + } + } + if (interface && interface != p->interface) { + prev_msg = " instead of "; + prev_mode = phy_modes(interface); + } else { + prev_msg = ""; + prev_mode = ""; + } + dev_info(dev->dev, + "Port%d: using phy mode %s%s%s\n", + i, + phy_modes(p->interface), + prev_msg, + prev_mode); + + /* enable cpu port */ + lan937x_port_setup(dev, i, true); + p->vid_member = dev->port_mask; + } + } + + dev->member = dev->host_mask; + + for (i = 0; i < dev->port_cnt; i++) { + if (i == dev->cpu_port) + continue; + p = &dev->ports[i]; + + /* Initialize to non-zero so that lan937x_cfg_port_member() will + * be called. + */ + p->vid_member = (1 << i); + p->member = dev->port_mask; + lan937x_port_stp_state_set(ds, i, BR_STATE_DISABLED); + } +} + +static int lan937x_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int ret = 0; + + dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), + dev->num_vlans, GFP_KERNEL); + if (!dev->vlan_cache) + return -ENOMEM; + + ret = lan937x_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + /* Required for port partitioning. */ + lan937x_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, + true); + + lan937x_config_cpu_port(ds); + + ds->configure_vlan_while_not_filtering = true; + + /* Enable aggressive back off & UNH */ + lan937x_cfg(dev, REG_SW_MAC_CTRL_0, SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF | + SW_AGGR_BACKOFF, true); + + lan937x_cfg(dev, REG_SW_MAC_CTRL_1, (MULTICAST_STORM_DISABLE + | NO_EXC_COLLISION_DROP), true); + + /* queue based egress rate limit */ + lan937x_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); + + lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true); + + /* enable global MIB counter freeze function */ + lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); + + /* enable Indirect Access from SPI to the VPHY registers */ + lan937x_enable_spi_indirect_access(dev); + + /* start switch */ + lan937x_cfg(dev, REG_SW_OPERATION, SW_START, true); + + ksz_init_mib_timer(dev); + + return 0; +} + +static int lan937x_change_mtu(struct dsa_switch *ds, int port, int mtu) +{ + struct ksz_device *dev = ds->priv; + u16 max_size; + + if (mtu >= FR_MIN_SIZE) { + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_JUMBO_EN, true); + max_size = FR_MAX_SIZE; + } else { + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_JUMBO_EN, false); + max_size = FR_MIN_SIZE; + } + /* Write the frame size in PORT_MAX_FR_SIZE register */ + lan937x_pwrite16(dev, port, PORT_MAX_FR_SIZE, max_size); + return 0; +} + +static int lan937x_get_max_mtu(struct dsa_switch *ds, int port) +{ + /* Frame size is 9000 (= 0x2328) if + * jumbo frame support is enabled, PORT_JUMBO_EN bit will be enabled + * based on mtu in lan937x_change_mtu() API + */ + return FR_MAX_SIZE; +} + +const struct dsa_switch_ops lan937x_switch_ops = { + .get_tag_protocol = lan937x_get_tag_protocol, + .setup = lan937x_setup, + .phy_read = lan937x_phy_read16, + .phy_write = lan937x_phy_write16, + .port_enable = ksz_enable_port, + .port_bridge_join = ksz_port_bridge_join, + .port_bridge_leave = ksz_port_bridge_leave, + .port_stp_state_set = lan937x_port_stp_state_set, + .port_fast_age = ksz_port_fast_age, + .port_max_mtu = lan937x_get_max_mtu, + .port_change_mtu = lan937x_change_mtu, +}; + +int lan937x_switch_register(struct ksz_device *dev) +{ + return ksz_switch_register(dev, &lan937x_dev_ops); +} +EXPORT_SYMBOL(lan937x_switch_register); + +MODULE_AUTHOR("Prasanna Vengateshan Varadharajan "); +MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h new file mode 100644 index 000000000000..d899a43f4d8e --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -0,0 +1,955 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip LAN937X switch register definitions + * Copyright (C) 2019-2020 Microchip Technology Inc. + */ +#ifndef __LAN937X_REG_H +#define __LAN937X_REG_H + +/* 0 - Operation */ +#define REG_CHIP_ID0__1 0x0000 +#define REG_CHIP_ID1__1 0x0001 +#define REG_CHIP_ID2__1 0x0002 + +#define CHIP_ID_74 0x74 +#define CHIP_ID_73 0x73 +#define CHIP_ID_72 0x72 +#define CHIP_ID_71 0x71 +#define CHIP_ID_70 0x70 + +#define REG_CHIP_ID3__1 0x0003 + +#define REG_GLOBAL_CTRL_0 0x0007 + +#define SW_PHY_REG_BLOCK BIT(7) +#define SW_FAST_MODE BIT(3) +#define SW_FAST_MODE_OVERRIDE BIT(2) + +#define REG_GLOBAL_OPTIONS 0x000F + +#define REG_SW_INT_STATUS__4 0x0010 +#define REG_SW_INT_MASK__4 0x0014 + +#define LUE_INT BIT(31) +#define TRIG_TS_INT BIT(30) +#define APB_TIMEOUT_INT BIT(29) +#define OVER_TEMP_INT BIT(28) +#define HSR_INT BIT(27) +#define PIO_INT BIT(26) +#define POR_READY_INT BIT(25) + +#define SWITCH_INT_MASK \ + (LUE_INT | TRIG_TS_INT | APB_TIMEOUT_INT | OVER_TEMP_INT | HSR_INT | \ + PIO_INT | POR_READY_INT) + +#define REG_SW_PORT_INT_STATUS__4 0x0018 +#define REG_SW_PORT_INT_MASK__4 0x001C + +/* 1 - Global */ +#define REG_SW_GLOBAL_SERIAL_CTRL_0 0x0100 + +#define SW_LITTLE_ENDIAN BIT(4) +#define SPI_AUTO_EDGE_DETECTION BIT(1) +#define SPI_CLOCK_OUT_RISING_EDGE BIT(0) + +#define REG_SW_GLOBAL_OUTPUT_CTRL__1 0x0103 +#define SW_ENABLE_REFCLKO BIT(1) +#define SW_REFCLKO_IS_125MHZ BIT(0) + +/* 2 - PHY */ +#define REG_SW_POWER_MANAGEMENT_CTRL 0x0201 + +/* 3 - Operation Control */ +#define REG_SW_OPERATION 0x0300 + +#define SW_DOUBLE_TAG BIT(7) +#define SW_OVER_TEMP_ENABLE BIT(2) +#define SW_RESET BIT(1) +#define SW_START BIT(0) + +#define REG_SW_LUE_CTRL_0 0x0310 +#define SW_VLAN_ENABLE BIT(7) +#define SW_DROP_INVALID_VID BIT(6) +#define SW_AGE_CNT_M 0x7 +#define SW_AGE_CNT_S 3 +#define SW_RESV_MCAST_ENABLE BIT(2) + +#define REG_SW_LUE_CTRL_1 0x0311 + +#define UNICAST_LEARN_DISABLE BIT(7) +#define SW_SRC_ADDR_FILTER BIT(6) +#define SW_FLUSH_STP_TABLE BIT(5) +#define SW_FLUSH_MSTP_TABLE BIT(4) +#define SW_FWD_MCAST_SRC_ADDR BIT(3) +#define SW_AGING_ENABLE BIT(2) +#define SW_FAST_AGING BIT(1) +#define SW_LINK_AUTO_AGING BIT(0) + +#define REG_SW_LUE_CTRL_2 0x0312 + +#define SW_MID_RANGE_AGE BIT(7) +#define SW_LINK_DOWN_FLUSH BIT(6) +#define SW_EGRESS_VLAN_FILTER_DYN BIT(5) +#define SW_EGRESS_VLAN_FILTER_STA BIT(4) +#define SW_FLUSH_OPTION_M 0x3 +#define SW_FLUSH_OPTION_S 2 +#define SW_FLUSH_OPTION_DYN_MAC 1 +#define SW_FLUSH_OPTION_STA_MAC 2 +#define SW_FLUSH_OPTION_BOTH 3 + +#define REG_SW_LUE_CTRL_3 0x0313 +#define REG_SW_AGE_PERIOD__1 0x0313 + +#define REG_SW_LUE_INT_STATUS__1 0x0314 +#define REG_SW_LUE_INT_MASK__1 0x0315 + +#define LEARN_FAIL_INT BIT(2) +#define WRITE_FAIL_INT BIT(0) + +#define LUE_INT_MASK (LEARN_FAIL_INT | WRITE_FAIL_INT) + +#define REG_SW_LUE_INDEX_0__2 0x0316 + +#define ENTRY_INDEX_M 0x0FFF + +#define REG_SW_LUE_INDEX_1__2 0x0318 + +#define FAIL_INDEX_M 0x03FF + +#define REG_SW_LUE_INDEX_2__2 0x031A + +#define REG_SW_STATIC_AVAIL_ENTRY__4 0x031C + +#define SW_INGRESS_FILTERING_NO_LEARN BIT(15) +#define SW_STATIC_AVAIL_CNT 0x1FF + +#define REG_SW_AGE_PERIOD__2 0x0320 +#define SW_AGE_PERIOD_M 0xFFF + +#define REG_SW_LUE_UNK_UCAST_CTRL__2 0x0322 +#define REG_SW_LUE_UNK_CTRL_0__4 0x0322 + +#define SW_UNK_UCAST_ENABLE BIT(15) +#define SW_UNK_PORTS_M 0xFF + +#define REG_SW_LUE_UNK_MCAST_CTRL__2 0x0324 +#define SW_UNK_MCAST_ENABLE BIT(15) + +#define REG_SW_LUE_UNK_VID_CTRL__2 0x0326 +#define SW_UNK_VID_ENABLE BIT(15) + +#define SW_VLAN_FLUSH_PORTS_M 0xFF + +#define REG_SW_STATIC_ENTRY_LIMIT__4 0x032C + +#define REG_SW_MAC_CTRL_0 0x0330 +#define SW_NEW_BACKOFF BIT(7) +#define SW_PAUSE_UNH_MODE BIT(1) +#define SW_AGGR_BACKOFF BIT(0) + +#define REG_SW_MAC_CTRL_1 0x0331 +#define SW_SHORT_IFG BIT(7) +#define MULTICAST_STORM_DISABLE BIT(6) +#define SW_BACK_PRESSURE BIT(5) +#define FAIR_FLOW_CTRL BIT(4) +#define NO_EXC_COLLISION_DROP BIT(3) +#define SW_LEGAL_PACKET_DISABLE BIT(1) +#define SW_PASS_SHORT_FRAME BIT(0) + +#define REG_SW_MAC_CTRL_2 0x0332 +#define SW_REPLACE_VID BIT(3) +#define BROADCAST_STORM_RATE_HI 0x07 + +#define REG_SW_MAC_CTRL_3 0x0333 +#define BROADCAST_STORM_RATE_LO 0xFF +#define BROADCAST_STORM_RATE 0x07FF + +#define REG_SW_MAC_CTRL_4 0x0334 +#define SW_PASS_PAUSE BIT(3) + +#define REG_SW_MAC_CTRL_5 0x0335 +#define SW_OUT_RATE_LIMIT_QUEUE_BASED BIT(3) + +#define REG_SW_MAC_CTRL_6 0x0336 +#define SW_MIB_COUNTER_FLUSH BIT(7) +#define SW_MIB_COUNTER_FREEZE BIT(6) + +#define REG_SW_MRI_CTRL_0 0x0370 +#define SW_IGMP_SNOOP BIT(6) +#define SW_IPV6_MLD_OPTION BIT(3) +#define SW_IPV6_MLD_SNOOP BIT(2) +#define SW_MIRROR_RX_TX BIT(0) + +#define REG_SW_MRI_CTRL_1__4 0x0374 +#define REG_SW_MRI_CTRL_2__4 0x0378 +#define REG_SW_CLASS_D_IP_CTRL__4 0x0374 + +#define SW_CLASS_D_IP_ENABLE BIT(31) + +#define REG_SW_MRI_CTRL_8 0x0378 +#define SW_RED_COLOR_S 4 +#define SW_YELLOW_COLOR_S 2 +#define SW_GREEN_COLOR_S 0 +#define SW_COLOR_M 0x3 + +#define REG_PTP_EVENT_PRIO_CTRL 0x037C +#define REG_PTP_GENERAL_PRIO_CTRL 0x037D +#define PTP_PRIO_ENABLE BIT(7) + +#define REG_SW_QM_CTRL__4 0x0390 +#define PRIO_SCHEME_SELECT_M KS_PRIO_M +#define PRIO_SCHEME_SELECT_S 6 +#define PRIO_MAP_3_HI 0 +#define PRIO_MAP_2_HI 2 +#define PRIO_MAP_0_LO 3 +#define UNICAST_VLAN_BOUNDARY BIT(1) + +#define REG_SW_EEE_QM_CTRL__2 0x03C0 +#define REG_SW_EEE_TXQ_WAIT_TIME__2 0x03C2 + +/* 4 - */ +#define REG_SW_VLAN_ENTRY__4 0x0400 +#define VLAN_VALID BIT(31) +#define VLAN_FORWARD_OPTION BIT(27) +#define VLAN_PRIO_M KS_PRIO_M +#define VLAN_PRIO_S 24 +#define VLAN_MSTP_M 0x7 +#define VLAN_MSTP_S 12 +#define VLAN_FID_M 0x7F + +#define REG_SW_VLAN_ENTRY_UNTAG__4 0x0404 +#define REG_SW_VLAN_ENTRY_PORTS__4 0x0408 +#define REG_SW_VLAN_ENTRY_INDEX__2 0x040C + +#define VLAN_INDEX_M 0x0FFF + +#define REG_SW_VLAN_CTRL 0x040E +#define VLAN_START BIT(7) +#define VLAN_ACTION 0x3 +#define VLAN_WRITE 1 +#define VLAN_READ 2 +#define VLAN_CLEAR 3 + +#define REG_SW_ALU_INDEX_0 0x0410 +#define ALU_FID_INDEX_S 16 +#define ALU_FID_SIZE 127 +#define ALU_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_INDEX_1 0x0414 +#define ALU_DIRECT_INDEX_M (BIT(12) - 1) + +#define REG_SW_ALU_CTRL__4 0x0418 +#define REG_SW_ALU_CTRL(num) (REG_SW_ALU_CTRL__4 + ((num) * 4)) + +#define ALU_STA_DYN_CNT 2 +#define ALU_VALID_CNT_M (BIT(14) - 1) +#define ALU_VALID_CNT_S 16 +#define ALU_START BIT(7) +#define ALU_VALID BIT(6) +#define ALU_VALID_OR_STOP BIT(5) +#define ALU_DIRECT BIT(2) +#define ALU_ACTION 0x3 +#define ALU_WRITE 1 +#define ALU_READ 2 +#define ALU_SEARCH 3 + +#define REG_SW_ALU_STAT_CTRL__4 0x041C +#define ALU_STAT_VALID_CNT_M (BIT(9) - 1) +#define ALU_STAT_VALID_CNT_S 20 +#define ALU_STAT_INDEX_M (BIT(8) - 1) +#define ALU_STAT_INDEX_S 8 +#define ALU_RESV_MCAST_INDEX_M (BIT(6) - 1) +#define ALU_STAT_START BIT(7) +#define ALU_STAT_VALID BIT(6) +#define ALU_STAT_VALID_OR_STOP BIT(5) +#define ALU_STAT_USE_FID BIT(4) +#define ALU_STAT_DIRECT BIT(3) +#define ALU_RESV_MCAST_ADDR BIT(2) +#define ALU_STAT_ACTION 0x3 +#define ALU_STAT_WRITE 1 +#define ALU_STAT_READ 2 +#define ALU_STAT_SEARCH 3 + +#define REG_SW_ALU_VAL_A 0x0420 +#define ALU_V_STATIC_VALID BIT(31) +#define ALU_V_SRC_FILTER BIT(30) +#define ALU_V_DST_FILTER BIT(29) +#define ALU_V_PRIO_AGE_CNT_M (BIT(3) - 1) +#define ALU_V_PRIO_AGE_CNT_S 26 +#define ALU_V_MSTP_M 0x7 + +#define REG_SW_ALU_VAL_B 0x0424 +#define ALU_V_OVERRIDE BIT(31) +#define ALU_V_USE_FID BIT(30) +#define ALU_V_PORT_MAP 0xFF + +#define REG_SW_ALU_VAL_C 0x0428 +#define ALU_V_FID_M (BIT(16) - 1) +#define ALU_V_FID_S 16 +#define ALU_V_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_VAL_D 0x042C + +#define PORT_CTRL_ADDR(port, addr) ((addr) | (((port) + 1) << 12)) + +#define REG_GLOBAL_RR_INDEX__1 0x0600 + +/* VPHY */ +#define REG_VPHY_CTRL__2 0x0700 +#define REG_VPHY_STAT__2 0x0704 +#define REG_VPHY_ID_HI__2 0x0708 +#define REG_VPHY_ID_LO__2 0x070C +#define REG_VPHY_AUTO_NEG__2 0x0710 +#define REG_VPHY_REMOTE_CAP__2 0x0714 + +#define REG_VPHY_EXPANSION__2 0x0718 + +#define REG_VPHY_M_CTRL__2 0x0724 +#define REG_VPHY_M_STAT__2 0x0728 + +#define REG_VPHY_EXT_STAT__2 0x073C +#define VPHY_EXT_1000_X_FULL BIT(15) +#define VPHY_EXT_1000_X_HALF BIT(14) +#define VPHY_EXT_1000_T_FULL BIT(13) +#define VPHY_EXT_1000_T_HALF BIT(12) + +#define REG_VPHY_DEVAD_0__2 0x0740 +#define REG_VPHY_DEVAD_1__2 0x0744 +#define REG_VPHY_DEVAD_2__2 0x0748 +#define REG_VPHY_DEVAD_3__2 0x074C + +#define VPHY_DEVAD_UPDATE BIT(7) +#define VPHY_DEVAD_M 0x1F +#define VPHY_DEVAD_S 8 + +#define REG_VPHY_SMI_ADDR__2 0x0750 +#define REG_VPHY_SMI_DATA_LO__2 0x0754 +#define REG_VPHY_SMI_DATA_HI__2 0x0758 + +#define REG_VPHY_IND_ADDR__2 0x075C +#define REG_VPHY_IND_DATA__2 0x0760 +#define REG_VPHY_IND_CTRL__2 0x0768 + +#define VPHY_IND_WRITE BIT(1) +#define VPHY_IND_BUSY BIT(0) + +#define REG_VPHY_SPECIAL_CTRL__2 0x077C +#define VPHY_SMI_INDIRECT_ENABLE BIT(15) +#define VPHY_SW_LOOPBACK BIT(14) +#define VPHY_MDIO_INTERNAL_ENABLE BIT(13) +#define VPHY_SPI_INDIRECT_ENABLE BIT(12) +#define VPHY_PORT_MODE_M 0x3 +#define VPHY_PORT_MODE_S 8 +#define VPHY_MODE_RGMII 0 +#define VPHY_MODE_MII_PHY 1 +#define VPHY_MODE_SGMII 2 +#define VPHY_MODE_RMII_PHY 3 +#define VPHY_SW_COLLISION_TEST BIT(7) +#define VPHY_SPEED_DUPLEX_STAT_M 0x7 +#define VPHY_SPEED_DUPLEX_STAT_S 2 +#define VPHY_SPEED_1000 BIT(4) +#define VPHY_SPEED_100 BIT(3) +#define VPHY_FULL_DUPLEX BIT(2) + +/* 0 - Operation */ +#define REG_PORT_DEFAULT_VID 0x0000 + +#define REG_PORT_CUSTOM_VID 0x0002 +#define REG_PORT_PME_STATUS 0x0013 + +#define REG_PORT_PME_CTRL 0x0017 +#define PME_WOL_MAGICPKT BIT(2) +#define PME_WOL_LINKUP BIT(1) +#define PME_WOL_ENERGY BIT(0) + +#define REG_PORT_INT_STATUS 0x001B +#define REG_PORT_INT_MASK 0x001F + +#define PORT_TAS_INT BIT(5) +#define PORT_SGMII_INT BIT(3) +#define PORT_PTP_INT BIT(2) +#define PORT_PHY_INT BIT(1) +#define PORT_ACL_INT BIT(0) + +#define PORT_INT_MASK \ + ( \ + PORT_TAS_INT | \ + PORT_SGMII_INT | PORT_PTP_INT | PORT_PHY_INT | PORT_ACL_INT) + +#define REG_PORT_CTRL_0 0x0020 + +#define PORT_MAC_LOOPBACK BIT(7) +#define PORT_MAC_REMOTE_LOOPBACK BIT(6) +#define PORT_K2L_INSERT_ENABLE BIT(5) +#define PORT_K2L_DEBUG_ENABLE BIT(4) +#define PORT_TAIL_TAG_ENABLE BIT(2) +#define PORT_QUEUE_SPLIT_ENABLE 0x3 + +#define REG_PORT_CTRL_1 0x0021 +#define PORT_SRP_ENABLE 0x3 + +#define REG_PORT_STATUS_0 0x0030 +#define PORT_INTF_SPEED_M 0x3 +#define PORT_INTF_SPEED_S 3 +#define PORT_INTF_FULL_DUPLEX BIT(2) +#define PORT_TX_FLOW_CTRL BIT(1) +#define PORT_RX_FLOW_CTRL BIT(0) + +#define REG_PORT_STATUS_1 0x0034 + +/* 1 - PHY */ +#define REG_VPHY_SMI_ADDR 0x14 +#define REG_VPHY_SMI_DATA_LO 0x15 +#define REG_VPHY_SMI_DATA_HI 0x16 + +#define REG_VPHY_SPECIAL_CTRL_STAT 0x1F + +#define REG_PORT_T1_PHY_BASIC_CTRL 0x00 + +#define PORT_T1_PHY_RESET BIT(15) +#define PORT_T1_PHY_LOOPBACK BIT(14) +#define PORT_T1_SPEED_100MBIT BIT(13) +#define PORT_T1_POWER_DOWN BIT(11) +#define PORT_T1_ISOLATE BIT(10) +#define PORT_T1_FULL_DUPLEX BIT(8) + +#define REG_PORT_T1_PHY_BASIC_STATUS 0x01 + +#define PORT_T1_MII_SUPPRESS_CAPABLE BIT(6) +#define PORT_T1_LINK_STATUS BIT(2) +#define PORT_T1_EXTENDED_CAPABILITY BIT(0) + +#define REG_PORT_T1_PHY_ID_HI 0x02 +#define REG_PORT_T1_PHY_ID_LO 0x03 + +#define LAN937X_T1_ID_HI 0x0007 +#define LAN937X_T1_ID_LO 0xC150 + +#define REG_PORT_T1_PHY_M_CTRL 0x09 + +#define PORT_T1_MANUAL_CFG BIT(12) +#define PORT_T1_M_CFG BIT(11) + +#define REG_PORT_T1_PHY_M_STATUS 0x0A + +#define PORT_T1_LOCAL_M BIT(14) +#define PORT_T1_LOCAL_RX_OK BIT(13) +#define PORT_T1_REMOTE_RX_OK BIT(12) +#define PORT_T1_IDLE_ERR_CNT_M 0xFF + +#define REG_PORT_T1_MDIO_CTRL_1 0x0F + +#define T1_MDIO_WAKE_OUT_PIN_REQ BIT(0) + +#define REG_PORT_T1_MDIO_CTRL_2 0x10 + +#define T1_MDIO_MDPREBP BIT(15) +#define T1_MDIO_PHYADBP BIT(14) +#define T1_MDIO_WAKE_REQ BIT(13) +#define T1_MDIO_SLEEP_REQ BIT(12) +#define TI_MDIO_CTRL_CLOCK_SKEW 0x0C00 +#define T1_MDIO_TX_TERNARY_SYM 0x0300 +#define T1_MDIO_PCS_SC_RESET BIT(7) +#define T1_MDIO_ENERGY_DETECT_M BIT(6) +#define T1_MDIO_IGNORE_IDLE BIT(5) +#define T1_MDIO_TIME_OUT_CNT 0x001E +#define T1_MDIO_TIME_OUT_ENABLE BIT(0) + +#define REG_PORT_T1_MODE_STAT 0x11 +#define T1_PORT_DSCR_LOCK_STATUS_MSK BIT(3) +#define T1_PORT_LINK_UP_MSK BIT(0) + +#define REG_PORT_T1_LOOPBACK_CTRL 0x12 + +#define REG_PORT_T1_RESET_CTRL 0x13 + +#define T1_PHYADDR_S 11 + +#define REG_PORT_T1_EXT_REG_CTRL 0x14 + +#define T1_PCS_STS_CNT_RESET BIT(15) +#define T1_IND_DATA_READ BIT(12) +#define T1_IND_DATA_WRITE BIT(11) +#define T1_REG_BANK_SEL_M 0x7 +#define T1_REG_BANK_SEL_S 8 +#define T1_REG_BANK_SEL_INST 5 +#define T1_REG_BANK_SEL_DSP 4 +#define T1_REG_BANK_SEL_AFE 3 +#define T1_REG_BANK_SEL_PCS 2 +#define T1_REG_BANK_SEL_MISC 1 +#define T1_REG_ADDR_M 0xFF + +#define REG_PORT_T1_EXT_REG_RD_DATA 0x15 +#define REG_PORT_T1_EXT_REG_WR_DATA 0x16 + +#define REG_PORT_T1_PCS_CTRL 0x17 + +#define REG_PORT_T1_PHY_INT_STATUS 0x18 +#define REG_PORT_T1_PHY_INT_ENABLE 0x19 + +#define T1_PHY_CTRL_MAXWAIT_TIMER_INT BIT(8) +#define T1_ZERO_TIMER_INT BIT(7) +#define T1_ENERGY_OFF_INT BIT(6) +#define T1_IDLE_ERR_THRESH_DET_INT BIT(4) +#define T1_LINK_UP_INT BIT(2) +#define T1_LINK_DOWN_INT BIT(1) +#define T1_ENERGY_ON_INT BIT(0) + +#define REG_PORT_T1_POWER_DOWN_CTRL 0x1A + +#define T1_BIST_LINK_UP BIT(15) +#define T1_EMERGENCY_STOP BIT(14) +#define T1_PTP_ENABLE BIT(13) +#define T1_PCS_LINK_CTRL_ENABLE BIT(12) +#define T1_DSP_START_EQUALIZER BIT(11) +#define T1_START_ZQ_CAL BIT(10) +#define T1_FORCE_TX_ENABLE BIT(9) +#define T1_HW_INIT_SEQ_ENABLE BIT(8) +#define T1_WAKE_ENABLE BIT(7) +#define T1_LINK_UP_REQ BIT(6) +#define T1_AUTO_CLR_EPDWRDOWN BIT(5) +#define T1_ENERGY_DETECT_POWER_DOWN BIT(4) +#define T1_FORCE_ENERGY_DETECT BIT(3) +#define T1_AUTO_SLEEP_WAKEUP BIT(2) +#define T1_ENERGY_DETECT_HW_ENABLE BIT(1) +#define T1_ENERGY_DETECT_ENABLE BIT(0) + +#define REG_PORT_T1_BIST_CTRL 0x1B +#define REG_PORT_T1_BIST_STAT 0x1C +#define REG_PORT_T1_BIST_ERR_CNT_STS 0x1D +#define REG_PORT_T1_PCS_RX_ERR_CNT_STS 0x1E +#define REG_PORT_T1_TS_CTRL_STAT 0x1F + +#define REG_PORT_T1_PCS_DESCRM_CTRL_0 0x00 + +#define T1_PCS_SEND_IDLE_LOC_RCV_STS BIT(15) +#define T1_PCS_DESCR_RELOCK_ON_IDLE BIT(14) +#define T1_PCS_DESCR_RELOCK_ON_RCV BIT(13) +#define T1_PCS_DESCR_RELOCK_ON_EQ BIT(12) +#define T1_PCS_DESCR_LOCK_SYM_CNT 0x0FC0 +#define T1_PCS_DESCR_LOCK_CHK_WIN 0x003F + +#define REG_PORT_T1_PCS_DESCRM_CTRL_1 0x01 + +#define T1_PCS_DESCR_PIPE_DELAY 0x0700 +#define T1_PCS_FEED_DESCR_LFSR_WIN 0x003F + +#define REG_PORT_T1_PCS_EQ_TIMER_CTRL 0x02 + +#define REG_PORT_T1_PCS_RX_ERR_CNT 0x0E + +#define REG_PORT_T1_PCS_ED_STABILITY 0x26 + +#define REG_PORT_TX_PHY_CTRL 0x00 +#define REG_PORT_TX_PHY_STATUS 0x01 +#define REG_PORT_TX_PHY_ID_HI 0x02 +#define REG_PORT_TX_PHY_ID_LO 0x03 +#define REG_PORT_TX_PHY_AUTO_NEG 0x04 +#define REG_PORT_TX_PHY_REMOTE_CAP 0x05 + +#define REG_PORT_TX_6 0x06 +#define REG_PORT_TX_7 0x07 +#define REG_PORT_TX_10 0x10 +#define REG_PORT_TX_11 0x11 + +#define REG_PORT_TX_SPECIAL_MODES 0x12 + +#define TX_SPECIAL_CFG_M 0x7 +#define TX_SPECIAL_CFG_S 5 +#define TX_PHYADDR_M 0x1F + +#define REG_PORT_TX_13 0x13 + +#define REG_PORT_TX_IND_CTRL 0x14 + +#define TX_IND_DATA_READ BIT(15) +#define TX_IND_DATA_WRITE BIT(14) +#define TX_REG_BANK_SEL_M 0x7 +#define TX_REG_BANK_SEL_S 11 +#define TX_REG_BANK_SEL_VMDAC 7 +#define TX_REG_BANK_SEL_BIST 3 +#define TX_REG_BANK_SEL_WOL 1 +#define TX_REG_BANK_SEL_DSP 0 +#define TX_TEST_MODE BIT(10) +#define TX_READ_ADDR_M 0x1F +#define TX_READ_ADDR_S 5 +#define TX_WRITE_ADDR_M 0x1F + +#define REG_PORT_TX_READ_DATA_LO 0x15 +#define REG_PORT_TX_READ_DATA_HI 0x16 +#define REG_PORT_TX_WRITE_DATA 0x17 + +#define REG_PORT_TX_PHY_INT_STATUS 0x1D +#define REG_PORT_TX_PHY_INT_ENABLE 0x1E + +#define TX_ENERGY_ON_INT BIT(7) +#define TX_AUTO_NEG_COMPLETE_INT BIT(6) +#define TX_LINK_DOWN_INT BIT(4) +#define TX_AUTO_NEG_ACK_INT BIT(3) +#define TX_AUTO_NEG_PAGE_RCV_INT BIT(1) + +#define REG_PORT_TX_1F 0x1F + +#define TX_DSP_DCBLW 0x00 + +#define TX_DSP_DCBLW_VAL 0x9aa2 + +#define TX_DSP_A5_CONFIG 0x16 + +#define TX_A5_TXCLKPHSEL_M 0x7 +#define TX_A5_TXCLKPHSEL_S 12 +#define TX_A5_TXCLK_0_NS 0 +#define TX_A5_TXCLK_1_NS 1 +#define TX_A5_TXCLK_2_NS 2 +#define TX_A5_TXCLK_3_NS 3 +#define TX_A5_TXCLK_4_NS 4 +#define TX_A5_TXCLK_5_NS 5 +#define TX_A5_TXCLK_6_NS 6 +#define TX_A5_TXCLK_7_NS 7 + +#define TX_DSP_A10_CONFIG 0x1C + +#define TX_DSP_A10_CONFIG_VAL 0x9000 + +#define TX_DSP_A11_CONFIG 0x1D + +#define TX_DSP_A11_CONFIG_VAL 0x7600 + +#define TX_BIST_FR_PLL_DIV0 0x1C +#define TX_BIST_FR_PLL_DIV1 0x1D + +#define TX_FR_PLL_DIV0 0x0 +#define TX_FR_PLL_DIV1 0x1280 + +#define TX_VMDAC_ZQ_CAL_CTRL 0x00 + +#define TX_START_ZQ_CAL BIT(0) +#define TX_BYPASS_ZQ_CAL BIT(1) + +#define TX_VMDAC_ZQ_CAL_STAT 0x01 + +#define TX_VMDAC_CTRL0 0x02 +#define TX_VDVREF_EN BIT(0) +#define TX_VDVEXT_EN BIT(1) +#define TX_A_ZEN BIT(11) +#define TX_A_RXZEN BIT(12) +#define TX_VD_INTIR_EN BIT(15) + +#define TX_VMDAC_CTRL0_VAL 0x9783 +#define TX_VMDAC_CTRL1 0x03 + +#define TX_10BT_VD_EN BIT(0) +#define TX_B_ZEN BIT(11) +#define TX_B_RXZEN BIT(12) +#define TX_VD_PD BIT(15) + +#define TX_VMDAC_CTRL1_VAL 0x7784 +#define TX_VMDAC_MISC_PCS_CTRL0 0x05 + +#define TX_MISC_PCS_CTRL0_13 BIT(13) +#define TX_VMDAC_MISC_PCS_CTRL1 0x06 + +#define REG_PORT_T1_PHY_CTRL_BASE 0x0100 +#define REG_PORT_TX_PHY_CTRL_BASE 0x0280 +#define REG_TX_PHY_CTRL_BASE 0x0980 + +#define REG_PORT_PHY_CTRL 0x0100 + +#define PORT_PHY_RESET BIT(15) +#define PORT_PHY_LOOPBACK BIT(14) +#define PORT_SPEED_100MBIT BIT(13) +#define PORT_AUTO_NEG_ENABLE BIT(12) +#define PORT_POWER_DOWN BIT(11) +#define PORT_ISOLATE BIT(10) +#define PORT_AUTO_NEG_RESTART BIT(9) +#define PORT_FULL_DUPLEX BIT(8) +#define PORT_COLLISION_TEST BIT(7) +#define PORT_SPEED_1000MBIT BIT(6) + +#define REG_PORT_PHY_STATUS 0x0102 + +#define PORT_100BT4_CAPABLE BIT(15) +#define PORT_100BTX_FD_CAPABLE BIT(14) +#define PORT_100BTX_CAPABLE BIT(13) +#define PORT_10BT_FD_CAPABLE BIT(12) +#define PORT_10BT_CAPABLE BIT(11) +#define PORT_EXTENDED_STATUS BIT(8) +#define PORT_MII_SUPPRESS_CAPABLE BIT(6) +#define PORT_AUTO_NEG_ACKNOWLEDGE BIT(5) +#define PORT_REMOTE_FAULT BIT(4) +#define PORT_AUTO_NEG_CAPABLE BIT(3) +#define PORT_LINK_STATUS BIT(2) +#define PORT_JABBER_DETECT BIT(1) +#define PORT_EXTENDED_CAPABILITY BIT(0) + +#define REG_PORT_PHY_ID_HI 0x0104 +#define REG_PORT_PHY_ID_LO 0x0106 + +#define LAN937X_ID_HI 0x0007 +#define LAN937X_ID_LO 0x1951 + +#define REG_PORT_PHY_1000_CTRL 0x0112 +#define PORT_AUTO_NEG_MANUAL BIT(12) +#define PORT_AUTO_NEG_M BIT(11) +#define PORT_AUTO_NEG_M_PREFERRED BIT(10) +#define PORT_AUTO_NEG_1000BT_FD BIT(9) +#define PORT_AUTO_NEG_1000BT BIT(8) + +#define REG_PORT_PHY_1000_STATUS 0x0114 + +#define REG_PORT_PHY_RXER_COUNTER 0x012A +#define REG_PORT_PHY_INT_ENABLE 0x0136 +#define REG_PORT_PHY_INT_STATUS 0x0137 + +/* Same as PORT_PHY_LOOPBACK */ +#define PORT_PHY_PCS_LOOPBACK BIT(0) + +#define REG_PORT_PHY_DIGITAL_DEBUG_2 0x013A + +#define REG_PORT_PHY_DIGITAL_DEBUG_3 0x013C +#define PORT_100BT_FIXED_LATENCY BIT(15) + +#define REG_PORT_PHY_PHY_CTRL 0x013E +#define PORT_INT_PIN_HIGH BIT(14) +#define PORT_ENABLE_JABBER BIT(9) +#define PORT_STAT_SPEED_1000MBIT BIT(6) +#define PORT_STAT_SPEED_100MBIT BIT(5) +#define PORT_STAT_SPEED_10MBIT BIT(4) +#define PORT_STAT_FULL_DUPLEX BIT(3) + +/* Same as PORT_PHY_STAT_M */ +#define PORT_STAT_M BIT(2) +#define PORT_RESET BIT(1) +#define PORT_LINK_STATUS_FAIL BIT(0) + +/* 3 - xMII */ +#define REG_PORT_XMII_CTRL_0 0x0300 +#define PORT_SGMII_SEL BIT(7) +#define PORT_MII_FULL_DUPLEX BIT(6) +#define PORT_MII_TX_FLOW_CTRL BIT(5) +#define PORT_MII_100MBIT BIT(4) +#define PORT_MII_RX_FLOW_CTRL BIT(3) +#define PORT_GRXC_ENABLE BIT(0) + +#define REG_PORT_XMII_CTRL_1 0x0301 +#define PORT_MII_NOT_1GBIT BIT(6) +#define PORT_MII_SEL_EDGE BIT(5) +#define PORT_RGMII_ID_IG_ENABLE BIT(4) +#define PORT_RGMII_ID_EG_ENABLE BIT(3) +#define PORT_MII_MAC_MODE BIT(2) +#define PORT_MII_SEL_M 0x3 +#define PORT_RGMII_SEL 0x0 +#define PORT_RMII_SEL 0x1 +#define PORT_MII_SEL 0x2 + +#define REG_PORT_XMII_CTRL_2 0x0302 +#define PORT_RGMII_RX_STS_ENABLE BIT(0) + +#define REG_PORT_XMII_CTRL_4 0x0304 +#define REG_PORT_XMII_CTRL_5 0x0305 + +/* 4 - MAC */ +#define REG_PORT_MAC_CTRL_0 0x0400 +#define PORT_CHECK_LENGTH BIT(2) +#define PORT_BROADCAST_STORM BIT(1) +#define PORT_JUMBO_PACKET BIT(0) + +#define REG_PORT_MAC_CTRL_1 0x0401 +#define PORT_BACK_PRESSURE BIT(3) +#define PORT_PASS_ALL BIT(0) + +#define REG_PORT_MAC_CTRL_2 0x0402 +#define PORT_100BT_EEE_DISABLE BIT(7) +#define PORT_1000BT_EEE_DISABLE BIT(6) + +#define REG_PORT_MAC_IN_RATE_LIMIT 0x0403 + +#define REG_PORT_MTU__2 0x0404 +#define PORT_RATE_LIMIT_M (BIT(7) - 1) + +/* 5 - MIB Counters */ +#define REG_PORT_MIB_CTRL_STAT__4 0x0500 +#define MIB_COUNTER_OVERFLOW BIT(31) +#define MIB_COUNTER_VALID BIT(30) +#define MIB_COUNTER_READ BIT(25) +#define MIB_COUNTER_FLUSH_FREEZE BIT(24) +#define MIB_COUNTER_INDEX_M (BIT(8) - 1) +#define MIB_COUNTER_INDEX_S 16 +#define MIB_COUNTER_DATA_HI_M 0xF + +#define REG_PORT_MIB_DATA 0x0504 + +/* 8 - Classification and Policing */ +#define REG_PORT_MRI_MIRROR_CTRL 0x0800 +#define PORT_MIRROR_RX BIT(6) +#define PORT_MIRROR_TX BIT(5) +#define PORT_MIRROR_SNIFFER BIT(1) + +#define REG_PORT_MRI_PRIO_CTRL 0x0801 +#define PORT_HIGHEST_PRIO BIT(7) +#define PORT_OR_PRIO BIT(6) +#define PORT_MAC_PRIO_ENABLE BIT(4) +#define PORT_VLAN_PRIO_ENABLE BIT(3) +#define PORT_802_1P_PRIO_ENABLE BIT(2) +#define PORT_DIFFSERV_PRIO_ENABLE BIT(1) +#define PORT_ACL_PRIO_ENABLE BIT(0) + +#define REG_PORT_MRI_MAC_CTRL 0x0802 +#define PORT_USER_PRIO_CEILING BIT(7) +#define PORT_DROP_NON_VLAN BIT(4) +#define PORT_DROP_TAG BIT(3) +#define PORT_BASED_PRIO_M KS_PRIO_M +#define PORT_BASED_PRIO_S 0 + +#define REG_PORT_MRI_TC_MAP__4 0x0808 + +/* 9 - Shaping */ +#define REG_PORT_MTI_QUEUE_INDEX__4 0x0900 + +#define REG_PORT_MTI_QUEUE_CTRL_0__4 0x0904 +#define MTI_PVID_REPLACE BIT(0) + +#define REG_PORT_MTI_QUEUE_CTRL_0 0x0914 + +/* A - QM */ +#define REG_PORT_QM_CTRL__4 0x0A00 +#define PORT_QM_DROP_PRIO_M 0x3 + +#define REG_PORT_VLAN_MEMBERSHIP__4 0x0A04 + +#define REG_PORT_QM_QUEUE_INDEX__4 0x0A08 +#define PORT_QM_QUEUE_INDEX_S 24 +#define PORT_QM_BURST_SIZE_S 16 +#define PORT_QM_MIN_RESV_SPACE_M (BIT(11) - 1) + +#define REG_PORT_QM_WATER_MARK__4 0x0A0C +#define PORT_QM_HI_WATER_MARK_S 16 +#define PORT_QM_LO_WATER_MARK_S 0 +#define PORT_QM_WATER_MARK_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_0__4 0x0A10 +#define PORT_QM_TX_CNT_USED_S 0 +#define PORT_QM_TX_CNT_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_1__4 0x0A14 +#define PORT_QM_TX_CNT_CALCULATED_S 16 +#define PORT_QM_TX_CNT_AVAIL_S 0 + +/* B - LUE */ +#define REG_PORT_LUE_CTRL 0x0B00 + +#define PORT_VLAN_LOOKUP_VID_0 BIT(7) +#define PORT_INGRESS_FILTER BIT(6) +#define PORT_DISCARD_NON_VID BIT(5) +#define PORT_MAC_BASED_802_1X BIT(4) +#define PORT_SRC_ADDR_FILTER BIT(3) + +#define REG_PORT_LUE_MSTP_INDEX 0x0B01 + +#define REG_PORT_LUE_MSTP_STATE 0x0B04 + +#define PORT_TX_ENABLE BIT(2) +#define PORT_RX_ENABLE BIT(1) +#define PORT_LEARN_DISABLE BIT(0) + +#define REG_PORT_LUE_LEARN_CNT__2 0x0B08 + +#define REG_PORT_LUE_UNK_UCAST_CTRL__2 0x0B0E +#define REG_PORT_LUE_UNK_MCAST_CTRL__2 0x0B10 +#define REG_PORT_LUE_UNK_VID_CTRL__2 0x0B12 + +#define PORT_UNK_UCAST_ENABLE BIT(15) +#define PORT_UNK_MCAST_ENABLE BIT(15) +#define PORT_UNK_VID_ENABLE BIT(15) + +#define PRIO_QUEUES 8 +#define RX_PRIO_QUEUES 8 +#define KS_PRIO_IN_REG 2 +#define TOTAL_PORT_NUM 8 + +#define LAN937X_COUNTER_NUM 0x20 +#define TOTAL_LAN937X_COUNTER_NUM (LAN937X_COUNTER_NUM + 2 + 2) + +#define SWITCH_COUNTER_NUM LAN937X_COUNTER_NUM + +#define P_BCAST_STORM_CTRL REG_PORT_MAC_CTRL_0 +#define P_PRIO_CTRL REG_PORT_MRI_PRIO_CTRL +#define P_MIRROR_CTRL REG_PORT_MRI_MIRROR_CTRL +#define P_STP_CTRL REG_PORT_LUE_MSTP_STATE +#define P_PHY_CTRL REG_PORT_PHY_CTRL +#define P_NEG_RESTART_CTRL REG_PORT_PHY_CTRL +#define P_LINK_STATUS REG_PORT_PHY_STATUS +#define P_SPEED_STATUS REG_PORT_PHY_PHY_CTRL +#define P_RATE_LIMIT_CTRL REG_PORT_MAC_IN_RATE_LIMIT + +#define S_LINK_AGING_CTRL REG_SW_LUE_CTRL_1 +#define S_MIRROR_CTRL REG_SW_MRI_CTRL_0 +#define S_REPLACE_VID_CTRL REG_SW_MAC_CTRL_2 +#define S_802_1P_PRIO_CTRL REG_SW_MAC_802_1P_MAP_0 +#define S_TOS_PRIO_CTRL REG_SW_MAC_TOS_PRIO_0 +#define S_FLUSH_TABLE_CTRL REG_SW_LUE_CTRL_1 + +#define REG_SWITCH_RESET REG_RESET_CTRL + +#define SW_FLUSH_DYN_MAC_TABLE SW_FLUSH_MSTP_TABLE + +#define MAX_TIMESTAMP_UNIT 2 +#define MAX_TRIG_UNIT 3 +#define MAX_TIMESTAMP_EVENT_UNIT 8 +#define MAX_GPIO 2 +#define MAX_CLOCK 2 + +#define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) +#define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) + +#define TAIL_TAG_PTP BIT(7) +#define TAIL_TAG_NEXT_CHIP BIT(6) +#define TAIL_TAG_K2L BIT(5) +#define TAIL_TAG_PTP_1_STEP BIT(4) +#define TAIL_TAG_PTP_P2P BIT(3) +#define TAIL_TAG_RX_PORTS_M 0x7 + +/* 148,800 frames * 67 ms / 100 */ +#define BROADCAST_STORM_VALUE 9969 + +#define SW_CHECK_LENGTH BIT(3) + +#define FR_MIN_SIZE 1522 +#define FR_MAX_SIZE 9000 + +#define PORT_JUMBO_EN BIT(0) +#define PORT_FR_CHK_LENGTH BIT(2) +#define PORT_MAX_FR_SIZE 0x404 + +#define FR_SIZE_CPU_PORT 1540 + +#define REG_PORT_CTRL_0 0x0020 +#define PORT_MAC_LOOPBACK BIT(7) +#define PORT_FORCE_TX_FLOW_CTRL BIT(5) +#define PORT_FORCE_RX_FLOW_CTRL BIT(3) + +#define PORT_QUEUE_SPLIT_ENABLE 0x3 + +/* Get fid from vid, fid 0 is not used if vid is greater than 127 */ +#define LAN937X_GET_FID(vid) (((vid) % ALU_FID_SIZE) + 1) + +/* Driver set switch broadcast storm protection at 10% rate. */ +#define BROADCAST_STORM_PROT_RATE 10 + +#define MII_BMSR_100BASE_TX_FD BIT(14) + +#define PHY_LINK_UP 1 +#define PHY_LINK_DOWN 0 + +/*The port number as per the datasheet*/ +#define RGMII_2_PORT_NUM 5 +#define RGMII_1_PORT_NUM 6 +#define SGMII_PORT_NUM 4 +#define TXPHY_PORT_NUM 4 + +#define GET_CHIP_ID_LSB(chip_id) (((chip_id) >> 8) & 0xff) +#define LAN937X_RGMII_2_PORT (RGMII_2_PORT_NUM - 1) +#define LAN937X_RGMII_1_PORT (RGMII_1_PORT_NUM - 1) +#define LAN937X_SGMII_PORT (SGMII_PORT_NUM - 1) +#define LAN937X_TXPHY_PORT (TXPHY_PORT_NUM - 1) + +#endif diff --git a/drivers/net/dsa/microchip/lan937x_spi.c b/drivers/net/dsa/microchip/lan937x_spi.c new file mode 100644 index 000000000000..20ee931c448d --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_spi.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip LAN937X switch driver register access through SPI + * Copyright (C) 2019-2020 Microchip Technology Inc. + */ +#include + +#include +#include +#include +#include +#include + +#include "ksz_common.h" + +#define SPI_ADDR_SHIFT 24 +#define SPI_ADDR_ALIGN 3 +#define SPI_TURNAROUND_SHIFT 5 + +KSZ_REGMAP_TABLE(lan937x, 32, SPI_ADDR_SHIFT, + SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN); + +static int lan937x_spi_probe(struct spi_device *spi) +{ + struct regmap_config rc; + struct ksz_device *dev; + int i, ret; + + dev = ksz_switch_alloc(&spi->dev, spi); + if (!dev) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(lan937x_regmap_config); i++) { + rc = lan937x_regmap_config[i]; + rc.lock_arg = &dev->regmap_mutex; + dev->regmap[i] = devm_regmap_init_spi(spi, &rc); + if (IS_ERR(dev->regmap[i])) { + ret = PTR_ERR(dev->regmap[i]); + dev_err(&spi->dev, + "Failed to initialize regmap%i: %d\n", + lan937x_regmap_config[i].val_bits, ret); + return ret; + } + } + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = lan937x_switch_register(dev); + + /* Main DSA driver may not be started yet. */ + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int lan937x_spi_remove(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev) + ksz_switch_remove(dev); + + return 0; +} + +static void lan937x_spi_shutdown(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev && dev->dev_ops->shutdown) + dev->dev_ops->shutdown(dev); +} + +static const struct of_device_id lan937x_dt_ids[] = { + { .compatible = "microchip,lan9370"}, + { .compatible = "microchip,lan9371"}, + { .compatible = "microchip,lan9372"}, + { .compatible = "microchip,lan9373"}, + { .compatible = "microchip,lan9374"}, + {}, +}; +MODULE_DEVICE_TABLE(of, lan937x_dt_ids); + +static struct spi_driver lan937x_spi_driver = { + .driver = { + .name = "lan937x-switch", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lan937x_dt_ids), + }, + .probe = lan937x_spi_probe, + .remove = lan937x_spi_remove, + .shutdown = lan937x_spi_shutdown, +}; + +module_spi_driver(lan937x_spi_driver); + +MODULE_ALIAS("spi:lan937x"); + +MODULE_AUTHOR("Prasanna Vengateshan Varadharajan "); +MODULE_DESCRIPTION("Microchip LAN937x Series Switch SPI access Driver"); +MODULE_LICENSE("GPL"); From patchwork Thu Jan 28 06:41:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12051999 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61326C433E9 for ; Thu, 28 Jan 2021 06:46:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1735764DDD for ; Thu, 28 Jan 2021 06:46:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231391AbhA1Gp5 (ORCPT ); Thu, 28 Jan 2021 01:45:57 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:29386 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229739AbhA1Gpp (ORCPT ); Thu, 28 Jan 2021 01:45:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816345; x=1643352345; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=j/e1p2gsEB8o2rRUpYQVXH49RlsT9/hWpFHmWN2Et/8=; b=raTpV+aInsAxp1fGG4JdKrm/JNLGaVoyv406fIAUDRZaPPe7FY4pzum0 LYceiKDnVz+T8iNcyz1Om6RbAKDrXcBIZg3CAJGJFz1ofR9sQnipei2qr sWAnJou9Xc8cB0GlSipNzEopX26tUVMb/pH3peFlYQ6xXbcFWAER5kyBv gLAfrpGl6nqoOAxKH+AlIKFv65GwidibEDWIwqCCyz54atCHiS4e8hi5f sGDzGfxrqRVkWmwhJ+k9cOoa7vGD3gZQ8Lm8+zNgdw8HOCLfy9idmjITe NQBruPrtmeuByZ6ofHYHiSs+AmvK0MqJHwKx+Exd2ApcpBqP1/pFtzwI/ g==; IronPort-SDR: 0CMhMKY16TsvN74qMHpq0D+HtmOsehNdVj8naJB7jzCCz1YsUK9DKEzJzZDcYCHYbeO1/59Wyx hjHUjxuzuDsmlZHlGpV+z9tk4mySSrx+nWrlNmmOOWoLX470bT72nKATotOWTdkxG/ze/9BFmt epR1J/rJC5Vfw6yQVq7L1nerHIUsUy2E6WEmwkYO6V3bKjKKgrGUi+eUOUMBi+KfNlGdzpjcOa bq3mrk9YKEqNYEgXmxC1X4aHJg86zuTcncyX/XY4kee5edK26f1K4JGr17G/BVxNxtZf0109Eh 28g= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="104520545" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:31 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.87.72) by chn-vm-ex02.mchp-main.com (10.10.87.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:30 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:25 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 4/8] net: dsa: microchip: add support for phylink management Date: Thu, 28 Jan 2021 12:11:08 +0530 Message-ID: <20210128064112.372883-5-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Support for phylink_validate() and reused KSZ commmon API for phylink_mac_link_down() operation Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_main.c | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 41f7f5f8f435..b38735e36aef 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -327,6 +327,44 @@ static int lan937x_get_max_mtu(struct dsa_switch *ds, int port) return FR_MAX_SIZE; } +static void lan937x_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct ksz_device *dev = ds->priv; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + if (phy_interface_mode_is_rgmii(state->interface) || + state->interface == PHY_INTERFACE_MODE_SGMII || + state->interface == PHY_INTERFACE_MODE_RMII || + state->interface == PHY_INTERFACE_MODE_MII || + lan937x_is_internal_tx_phy_port(dev, port)) { + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, Autoneg); + phylink_set_port_modes(mask); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + } + /* For RGMII & SGMII interfaces */ + if (phy_interface_mode_is_rgmii(state->interface) || + state->interface == PHY_INTERFACE_MODE_SGMII) { + phylink_set(mask, 1000baseT_Full); + } + /* For T1 PHY */ + if (lan937x_is_internal_t1_phy_port(dev, port)) { + phylink_set(mask, 100baseT_Full); + phylink_set_port_modes(mask); + } + + bitmap_and(supported, supported, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .setup = lan937x_setup, @@ -339,6 +377,8 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_fast_age = ksz_port_fast_age, .port_max_mtu = lan937x_get_max_mtu, .port_change_mtu = lan937x_change_mtu, + .phylink_validate = lan937x_phylink_validate, + .phylink_mac_link_down = ksz_mac_link_down, }; int lan937x_switch_register(struct ksz_device *dev) From patchwork Thu Jan 28 06:41:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052015 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0687C433E0 for ; Thu, 28 Jan 2021 06:49:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7C8D764DA1 for ; Thu, 28 Jan 2021 06:49:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229834AbhA1GtU (ORCPT ); Thu, 28 Jan 2021 01:49:20 -0500 Received: from esa.microchip.iphmx.com ([68.232.153.233]:10106 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231484AbhA1GrA (ORCPT ); Thu, 28 Jan 2021 01:47:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816420; x=1643352420; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CJ86UUKaMEUWVhcvbzeSVDsrGyjAILrA2OIyBFsXvMM=; b=1+02it4XRxapECFO3vDfviaPkJTvJ5WoJCdu2zFG1x/Kjjt+h64R6Jaz X+zQ6h97u5tqAynI+69h4WCsD1f3hvEEleODojNtf6XMMBvEyYjcFAC90 DIdi/HeQa9LoinK3VSfTxo4b67pQbQENyy73zXw1gkT4onJeBlCyJnOr7 JRLol8Fg/3R2UMnIaYQ2fl8vZh4tJcTHjetONjRvRxSd4tkk6TJMscTDq GJaD+Ao3xSNeEesppulIosShaMse7XRviPiRJYesR8UdzkcLWyF5bVfNZ HM5qbV2N+LUY07E41OoQ8sEc8V4OaYPMOQeNMjANL3sz64/voZ0ZHMI+G w==; IronPort-SDR: SZ2ETMDEkiHwAt2jPfEDGwf6clOfQc+3Aqd7zNmzxX9h4IgBVvOMOROLgW/sYZmSccG925MWpO xp8uOJYN+BkMiWrUeOBXVCAXFnMKryY2duMuHQKabwng6GV85oudUCPXloPsGRgKNZmweP6qXg KGC4cIEnxjD+lgQESAITb4sgymQpcWWdxDRwITZxtRPKl0rDRzlVbrRB1FpMrWDCYnunEx3cXa IR9nP2x8uqpjvc6GBh3ggUtDMDp9xo5g616qWeqsg0slQHtwOI1y1RMVi+Im8mQ68JWnCdmw5Z etI= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="107076592" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa5.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:37 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:35 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:31 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 5/8] net: dsa: microchip: add support for ethtool port counters Date: Thu, 28 Jan 2021 12:11:09 +0530 Message-ID: <20210128064112.372883-6-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Reused the KSZ common APIs for get_ethtool_stats() & get_sset_count() along with relevant lan937x hooks for KSZ common layer and added support for get_strings() Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_dev.c | 36 ++++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_main.c | 18 ++++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c index 84540180ff2f..20ee485fb796 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.c +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -209,6 +209,40 @@ static void lan937x_flush_dyn_mac_table(struct ksz_device *dev, int port) } } +static void lan937x_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, + u64 *cnt) +{ + unsigned int val; + u32 data; + int ret; + + /* Enable MIB Counter read*/ + data = MIB_COUNTER_READ; + data |= (addr << MIB_COUNTER_INDEX_S); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); + + ret = regmap_read_poll_timeout(dev->regmap[2], + PORT_CTRL_ADDR(port, + REG_PORT_MIB_CTRL_STAT__4), + val, !(val & MIB_COUNTER_READ), 10, 1000); + /* failed to read MIB. get out of loop */ + if (ret) { + dev_err(dev->dev, "Failed to get MIB\n"); + return; + } + + /* count resets upon read */ + lan937x_pread32(dev, port, REG_PORT_MIB_DATA, &data); + *cnt += data; +} + +static void lan937x_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, + u64 *dropped, u64 *cnt) +{ + addr = lan937x_mib_names[addr].index; + lan937x_r_mib_cnt(dev, port, addr, cnt); +} + static void lan937x_port_init_cnt(struct ksz_device *dev, int port) { struct ksz_port_mib *mib = &dev->ports[port].mib; @@ -851,6 +885,8 @@ const struct ksz_dev_ops lan937x_dev_ops = { .cfg_port_member = lan937x_cfg_port_member, .flush_dyn_mac_table = lan937x_flush_dyn_mac_table, .port_setup = lan937x_port_setup, + .r_mib_cnt = lan937x_r_mib_cnt, + .r_mib_pkt = lan937x_r_mib_pkt, .port_init_cnt = lan937x_port_init_cnt, .shutdown = lan937x_reset_switch, .detect = lan937x_switch_detect, diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index b38735e36aef..5693c59df497 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -69,6 +69,21 @@ static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg, return lan937x_t1_tx_phy_write(dev, addr, reg, val); } +static void lan937x_get_strings(struct dsa_switch *ds, int port, + u32 stringset, uint8_t *buf) +{ + struct ksz_device *dev = ds->priv; + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < dev->mib_cnt; i++) { + memcpy(buf + i * ETH_GSTRING_LEN, lan937x_mib_names[i].string, + ETH_GSTRING_LEN); + } +} + static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { @@ -371,6 +386,9 @@ const struct dsa_switch_ops lan937x_switch_ops = { .phy_read = lan937x_phy_read16, .phy_write = lan937x_phy_write16, .port_enable = ksz_enable_port, + .get_strings = lan937x_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, From patchwork Thu Jan 28 06:41:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052011 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A975C433DB for ; Thu, 28 Jan 2021 06:47:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C737664DD9 for ; Thu, 28 Jan 2021 06:47:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231485AbhA1GrA (ORCPT ); Thu, 28 Jan 2021 01:47:00 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:29386 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231424AbhA1GqP (ORCPT ); Thu, 28 Jan 2021 01:46:15 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816374; x=1643352374; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=71Mg6U+AYgcqKsgprhctms49xl0Ct0S0CM972OvFfCU=; b=DVM8YmIhxc54HeAQwwlaRaeGOXrZx4eeLx4M0Ct3ZZB4SMAKOuLhE1Cz i84bxGOher6pKeKyXPNposIS2afayUwohSXX7klQBUVJ47w48Djpj18No bhrJldQAItQXuxcTh81Fw2UVeoAsLbZzvvaUwLfSZwbm2NdEPDSiUfhZO /NTpCVsyCVBIxV4C43btMhbpYOUUYy4aPL693miWHEphQcZHtoTkT6DbC ZlhsKgLRGSBVKXO2BOO7jEwfcg9YB+rft1m/QC6EWoeuGFtR7eFJVmFR/ urv8FBQ3fsZxRoFNtkoia2V8lufWSk29po0pQuByITs1TN80HZs21OGOE A==; IronPort-SDR: SFnSCSWYaQ+FWtZb129AuO9xPvWJkhgX+I34QtWAcX+N20nbL8Ap8rGgwo01RBmGTEO+Ik5hAz +Xk6suz6RlhKFppkTigy99/8lwNlL4lxS0ApMRmN5i7fxwwSyBoevh0xpcNKOwuVLlLIgzPNiR jP7Y8RCuazZRdIbg1CpIPyjZrWS+pCRDdrfGbf0ZybnZeyBrJG+/0bL9JYuSpw5Cos7RP3EzyH YP+O6Q9DMoHYGpbmoBLPfaXfQjTCJLM7hIJeAzQfMiX52WlozB3PTmkjWrvA7O35PwRQQWl6EA MS8= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="104520577" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:41 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.87.72) by chn-vm-ex02.mchp-main.com (10.10.87.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:41 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:36 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 6/8] net: dsa: microchip: add support for port mirror operations Date: Thu, 28 Jan 2021 12:11:10 +0530 Message-ID: <20210128064112.372883-7-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Added support for port_mirror_add() and port_mirror_del operations Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_main.c | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 5693c59df497..aa2efa4e5823 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -162,6 +162,46 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, mutex_unlock(&dev->dev_mutex); } +static int lan937x_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct ksz_device *dev = ds->priv; + + if (ingress) + lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); + else + lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); + + lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); + + /* configure mirror port */ + lan937x_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, true); + + lan937x_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); + + return 0; +} + +static void lan937x_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + if (mirror->ingress) + lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); + else + lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); + + lan937x_pread8(dev, port, P_MIRROR_CTRL, &data); + + if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) + lan937x_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, false); +} + static phy_interface_t lan937x_get_interface(struct ksz_device *dev, int port) { phy_interface_t interface; @@ -393,6 +433,8 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, .port_fast_age = ksz_port_fast_age, + .port_mirror_add = lan937x_port_mirror_add, + .port_mirror_del = lan937x_port_mirror_del, .port_max_mtu = lan937x_get_max_mtu, .port_change_mtu = lan937x_change_mtu, .phylink_validate = lan937x_phylink_validate, From patchwork Thu Jan 28 06:41:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052003 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B047C433DB for ; Thu, 28 Jan 2021 06:46:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1D03E64DD6 for ; Thu, 28 Jan 2021 06:46:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231442AbhA1GqT (ORCPT ); Thu, 28 Jan 2021 01:46:19 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:3043 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231418AbhA1GqH (ORCPT ); Thu, 28 Jan 2021 01:46:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816367; x=1643352367; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=L2YbG6neRTTwbRjDueKVetunN5vOYg7Q+iDPWDIOUc8=; b=VW9oPj48lP6u8LEzUyTuwGsV6feJ0MoVwYNRCSDmt8Hm5hnuD4w6evqN Lt5GGsv5gK1XGDh7k/Y2ug9AxGZyMhJF8R1Xe3QhcMaCmd+4aNbkTmauT SzO7/nYs4fFXq2ilgEKqqpCMxcEZYipX+1J24a9Pic8cLnAHGv+apof8e mdz9JSr1qDPDMMURLCLQ5VoC3oo97nVk1FHaId1bVofD+nXMNnMCnDICi oD9jEv/Hv2XN0D6zhpWmnSOfjg+C2KUTAQ1TjCj3jA6t1zHncY3faS1QI wa0OQ0ApvExUlZNRevKjbPUweCXH8dbyrzg5HQLKqz329xXUuWrQOfb51 A==; IronPort-SDR: a/y7t6CDc3xOdRGjAwp9Nutfk+OrFLGJLR2AMB8My8Q7VKUXDf60uZpaKM1NCiCuLXpOG5nMEw GjuXMeMCPG+6beAZHsetp1uk2+U9x1NW8r+MSXxpZCB6CGaRdyb6G4d4M37L3hj66FVySTpM8m jIMKi2BU9qGSipsgosxmrnWTJAKI1z1+w5Caq/ICqJe0yF0HqhiTMEMaJDMYetHLhgY4Fsc1n+ v0JGe8QAplSTgpvPK9N0AI7amC2VqHe+8NSeq43yKFkIi3O9eT3dTw0MEepmR8WYr9tusme7l0 B00= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="101713994" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:47 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.87.72) by chn-vm-ex02.mchp-main.com (10.10.87.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:46 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:41 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 7/8] net: dsa: microchip: add support for fdb and mdb management Date: Thu, 28 Jan 2021 12:11:11 +0530 Message-ID: <20210128064112.372883-8-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Support for fdb_add, mdb_add, fdb_del, mdb_del and fdb_dump operations It aligns with latest update of removing switchdev transactional logic from mdb entries Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_main.c | 424 +++++++++++++++++++++++ 1 file changed, 424 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index aa2efa4e5823..cd902addce3f 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -14,6 +14,42 @@ #include "ksz_common.h" #include "lan937x_dev.h" +static void lan937x_read_table(struct ksz_device *dev, u32 *table) +{ + /* read alu table */ + ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); + ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); +} + +static void lan937x_write_table(struct ksz_device *dev, u32 *table) +{ + /* write alu table */ + ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); + ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); + ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); + ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); +} + +static int lan937x_wait_alu_ready(int alu, struct ksz_device *dev) +{ + unsigned int val; + + return regmap_read_poll_timeout(dev->regmap[2], REG_SW_ALU_CTRL(alu), + val, !(val & ALU_START), 10, 1000); +} + +static int lan937x_wait_alu_sta_ready(struct ksz_device *dev) +{ + unsigned int val; + + return regmap_read_poll_timeout(dev->regmap[2], + REG_SW_ALU_STAT_CTRL__4, + val, !(val & ALU_STAT_START), + 10, 1000); +} + static enum dsa_tag_protocol lan937x_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp) @@ -162,6 +198,389 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, mutex_unlock(&dev->dev_mutex); } +static u8 lan937x_get_fid(u16 vid) +{ + if (vid > ALU_FID_SIZE) + return LAN937X_GET_FID(vid); + else + return vid; +} + +static int lan937x_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct ksz_device *dev = ds->priv; + u8 fid = lan937x_get_fid(vid); + u32 alu_table[4]; + int ret, i; + u32 data; + u8 val; + + mutex_lock(&dev->alu_mutex); + + for (i = 0; i < ALU_STA_DYN_CNT; i++) { + /* find any entry with mac & fid */ + data = fid << ALU_FID_INDEX_S; + data |= ((addr[0] << 8) | addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((addr[2] << 24) | (addr[3] << 16)); + data |= ((addr[4] << 8) | addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL(i), ALU_READ | ALU_START); + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret) { + dev_err(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + /* read ALU entry */ + lan937x_read_table(dev, alu_table); + + /* update ALU entry */ + alu_table[0] = ALU_V_STATIC_VALID; + + /* update port number */ + alu_table[1] |= BIT(port); + + if (fid) + alu_table[1] |= ALU_V_USE_FID; + alu_table[2] = (fid << ALU_V_FID_S); + alu_table[2] |= ((addr[0] << 8) | addr[1]); + alu_table[3] = ((addr[2] << 24) | (addr[3] << 16)); + alu_table[3] |= ((addr[4] << 8) | addr[5]); + + lan937x_write_table(dev, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL(i), ALU_WRITE | ALU_START); + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + + if (ret) + dev_err(dev->dev, "Failed to write ALU\n"); + + ksz_read8(dev, REG_SW_LUE_INT_STATUS__1, &val); + + /* ALU write failed */ + if (val & WRITE_FAIL_INT && i == 1) + dev_err(dev->dev, "Failed to write ALU\n"); + + /* ALU1 write failed and attempt to write ALU2, otherwise exit*/ + if (val & WRITE_FAIL_INT) + val = WRITE_FAIL_INT; + else + goto exit; + } + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int lan937x_port_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct ksz_device *dev = ds->priv; + u8 fid = lan937x_get_fid(vid); + u32 alu_table[4]; + int ret, i; + u32 data; + + mutex_lock(&dev->alu_mutex); + + for (i = 0; i < ALU_STA_DYN_CNT; i++) { + /* read any entry with mac & fid */ + data = fid << ALU_FID_INDEX_S; + data |= ((addr[0] << 8) | addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((addr[2] << 24) | (addr[3] << 16)); + data |= ((addr[4] << 8) | addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL(i), ALU_READ | ALU_START); + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret) { + dev_err(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); + if (alu_table[0] & ALU_V_STATIC_VALID) { + ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); + + /* clear forwarding port */ + alu_table[1] &= ~BIT(port); + + /* if there is no port to forward, clear table */ + if ((alu_table[1] & ALU_V_PORT_MAP) == 0) { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + } else { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + + lan937x_write_table(dev, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL(i), ALU_WRITE | ALU_START); + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret) + dev_err(dev->dev, "Failed to write ALU\n"); + } + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static void lan937x_convert_alu(struct lan_alu_struct *alu, u32 *alu_table) +{ + alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID); + alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER); + alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER); + alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) & + ALU_V_PRIO_AGE_CNT_M; + alu->mstp = alu_table[0] & ALU_V_MSTP_M; + + alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE); + alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID); + alu->port_forward = alu_table[1] & ALU_V_PORT_MAP; + + alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M; + + alu->mac[0] = (alu_table[2] >> 8) & 0xFF; + alu->mac[1] = alu_table[2] & 0xFF; + alu->mac[2] = (alu_table[3] >> 24) & 0xFF; + alu->mac[3] = (alu_table[3] >> 16) & 0xFF; + alu->mac[4] = (alu_table[3] >> 8) & 0xFF; + alu->mac[5] = alu_table[3] & 0xFF; +} + +static int lan937x_port_fdb_dump(struct dsa_switch *ds, int port, + dsa_fdb_dump_cb_t *cb, void *data) +{ + struct ksz_device *dev = ds->priv; + struct lan_alu_struct alu; + u32 lan937x_data; + u32 alu_table[4]; + int ret, i; + int timeout; + + mutex_lock(&dev->alu_mutex); + + for (i = 0; i < ALU_STA_DYN_CNT; i++) { + /* start ALU search */ + ksz_write32(dev, REG_SW_ALU_CTRL(i), ALU_START | ALU_SEARCH); + + do { + timeout = 1000; + do { + ksz_read32(dev, REG_SW_ALU_CTRL(i), &lan937x_data); + if ((lan937x_data & ALU_VALID) || !(lan937x_data & ALU_START)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (!timeout) { + dev_err(dev->dev, "Failed to search ALU\n"); + ret = -ETIMEDOUT; + goto exit; + } + + /* read ALU table */ + lan937x_read_table(dev, alu_table); + + lan937x_convert_alu(&alu, alu_table); + + if (alu.port_forward & BIT(port)) { + ret = cb(alu.mac, alu.fid, alu.is_static, data); + if (ret) + goto exit; + } + } while (lan937x_data & ALU_START); + +exit: + /* stop ALU search & continue to next ALU if available */ + ksz_write32(dev, REG_SW_ALU_CTRL(i), 0); + } + + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int lan937x_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct ksz_device *dev = ds->priv; + u8 fid = lan937x_get_fid(mdb->vid); + u32 static_table[4]; + u32 mac_hi, mac_lo; + int err = 0; + int index; + u32 data; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + err = lan937x_wait_alu_sta_ready(dev); + if (err) { + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + lan937x_read_table(dev, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same fid & mac address */ + if (((static_table[2] >> ALU_V_FID_S) == fid) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + static_table[3] == mac_lo) { + /* found matching one */ + break; + } + } else { + /* found empty one */ + break; + } + } + + /* no available entry */ + if (index == dev->num_statics) { + err = -ENOSPC; + goto exit; + } + + /* add entry */ + static_table[0] = ALU_V_STATIC_VALID; + + static_table[1] |= BIT(port); + if (fid) + static_table[1] |= ALU_V_USE_FID; + static_table[2] = (fid << ALU_V_FID_S); + static_table[2] |= mac_hi; + static_table[3] = mac_lo; + + lan937x_write_table(dev, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + if (lan937x_wait_alu_sta_ready(dev)) + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + return err; +} + +static int lan937x_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct ksz_device *dev = ds->priv; + u8 fid = lan937x_get_fid(mdb->vid); + u32 static_table[4]; + u32 mac_hi, mac_lo; + int index, ret; + u32 data; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret) { + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + lan937x_read_table(dev, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same fid & mac address */ + + if (((static_table[2] >> ALU_V_FID_S) == fid) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + static_table[3] == mac_lo) { + /* found matching one */ + break; + } + } + } + + /* no available entry */ + if (index == dev->num_statics) + goto exit; + + /* clear port based on port arg */ + static_table[1] &= ~BIT(port); + + if ((static_table[1] & ALU_V_PORT_MAP) == 0) { + /* delete entry */ + static_table[0] = 0; + static_table[1] = 0; + static_table[2] = 0; + static_table[3] = 0; + } + + lan937x_write_table(dev, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret) + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + static int lan937x_port_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, bool ingress) @@ -433,6 +852,11 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, .port_fast_age = ksz_port_fast_age, + .port_fdb_dump = lan937x_port_fdb_dump, + .port_fdb_add = lan937x_port_fdb_add, + .port_fdb_del = lan937x_port_fdb_del, + .port_mdb_add = lan937x_port_mdb_add, + .port_mdb_del = lan937x_port_mdb_del, .port_mirror_add = lan937x_port_mirror_add, .port_mirror_del = lan937x_port_mirror_del, .port_max_mtu = lan937x_get_max_mtu, From patchwork Thu Jan 28 06:41:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12052005 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91341C4332B for ; Thu, 28 Jan 2021 06:46:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6030964DD6 for ; Thu, 28 Jan 2021 06:46:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231452AbhA1Gqb (ORCPT ); Thu, 28 Jan 2021 01:46:31 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:10607 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231347AbhA1GqI (ORCPT ); Thu, 28 Jan 2021 01:46:08 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1611816368; x=1643352368; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=k/LpW9ZLWg6XuYfZ2wxuCNVHoLBJD/igf9dgOMJ1fHM=; b=AQfJl7poN8HWJK13AgkzzZmAD34zTQRkUwkoi1AVWDXO5V1AZBPodlCR TMWcZQ3JSwx7+iWASK2SzPwXbch9UhI0JC6ayd2Uq6mC5JF115bNl8ubn TKj+wuiZiUj99trlv29d/KKzeHd3hcC8LCJI0Aj1kmDt/OyF/ERY26OfK 8dcjvXWuGd5jzOoAcKC5xxCbmmIOuGZ8dzkBKEDYmjX7AhIlInS6HDBUV RPuNPRllAEzLD8GTKOt9BYGSRnuCny8tsD9ubeBdIDAFrEjrYX91NLIiG 4j+lBM0cdxk8N74YNKtuEY+NEl38sKhGgb9FPeq2IZGlcX8d8V2x7mD12 A==; IronPort-SDR: fdaOdcRNa4P0dD+3hQEaBqJLSlvtMZG2atrmqu3nFduFI/X4/lZHvdFDccslbAACoqk8LTdbfr w9teYlCaqDvhdjfCBxdHn6FnDvDSVsDTT4qooKvgdSYhEQ6Xzg0DVIE14ciaee0C61IhYpf1tA Bvpxk0HWeRq8zwhHoN/vM0sx1ESc3i0MAsJjQsV1wjZBOG2DTLb6abmyYClHum5qRVY4pbVCyE bBLws9EMg4aYgJTppGPEy4rIbgJQhLOY6sB7VAAnKmFdhItVWjcm4XNQRzRBKguZAqLzIQ+ypU PmQ= X-IronPort-AV: E=Sophos;i="5.79,381,1602572400"; d="scan'208";a="42047643" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Jan 2021 23:44:52 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 27 Jan 2021 23:44:51 -0700 Received: from CHE-LT-I21427U.microchip.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Wed, 27 Jan 2021 23:44:47 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , Subject: [PATCH net-next 8/8] net: dsa: microchip: add support for vlan operations Date: Thu, 28 Jan 2021 12:11:12 +0530 Message-ID: <20210128064112.372883-9-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> References: <20210128064112.372883-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Support for VLAN add, del, prepare and filtering operations. It aligns with latest update of removing switchdev transactional logic from VLAN objects Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_main.c | 161 +++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index cd902addce3f..b4c68baf9281 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -14,6 +14,73 @@ #include "ksz_common.h" #include "lan937x_dev.h" +static int lan937x_wait_vlan_ctrl_ready(struct ksz_device *dev) +{ + unsigned int val; + + return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, + val, !(val & VLAN_START), 10, 1000); +} + +static int lan937x_get_vlan_table(struct ksz_device *dev, u16 vid, + u32 *vlan_table) +{ + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret) + goto exit; + + ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]); + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static int lan937x_set_vlan_table(struct ksz_device *dev, u16 vid, + u32 *vlan_table) +{ + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret) + goto exit; + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + + /* update vlan cache table */ + dev->vlan_cache[vid].table[0] = vlan_table[0]; + dev->vlan_cache[vid].table[1] = vlan_table[1]; + dev->vlan_cache[vid].table[2] = vlan_table[2]; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + static void lan937x_read_table(struct ksz_device *dev, u32 *table) { /* read alu table */ @@ -198,6 +265,97 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, mutex_unlock(&dev->dev_mutex); } +static int lan937x_port_vlan_filtering(struct dsa_switch *ds, int port, + bool flag) +{ + struct ksz_device *dev = ds->priv; + + if (flag) { + lan937x_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, true); + lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); + } else { + lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); + lan937x_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, false); + } + + return 0; +} + +static int lan937x_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct ksz_device *dev = ds->priv; + u32 vlan_table[3]; + int err; + + err = lan937x_get_vlan_table(dev, vlan->vid, vlan_table); + if (err) { + dev_err(dev->dev, "Failed to get vlan table\n"); + return err; + } + + vlan_table[0] = VLAN_VALID | (vlan->vid & VLAN_FID_M); + + /* set/clear switch port when updating vlan table registers */ + if (untagged) + vlan_table[1] |= BIT(port); + else + vlan_table[1] &= ~BIT(port); + vlan_table[1] &= ~(BIT(dev->cpu_port)); + + vlan_table[2] |= BIT(port) | + BIT(dev->cpu_port); + + err = lan937x_set_vlan_table(dev, vlan->vid, vlan_table); + if (err) { + dev_err(dev->dev, "Failed to set vlan table\n"); + return err; + } + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + lan937x_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vlan->vid); + + return 0; +} + +static int lan937x_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct ksz_device *dev = ds->priv; + u32 vlan_table[3]; + u16 pvid; + + lan937x_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); + pvid = pvid & 0xFFF; + + if (lan937x_get_vlan_table(dev, vlan->vid, vlan_table)) { + dev_err(dev->dev, "Failed to get vlan table\n"); + return -ETIMEDOUT; + } + /* clear switch port number */ + vlan_table[2] &= ~BIT(port); + + if (pvid == vlan->vid) + pvid = 1; + + if (untagged) + vlan_table[1] &= ~BIT(port); + + if (lan937x_set_vlan_table(dev, vlan->vid, vlan_table)) { + dev_err(dev->dev, "Failed to set vlan table\n"); + return -ETIMEDOUT; + } + + lan937x_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); + + return 0; +} + static u8 lan937x_get_fid(u16 vid) { if (vid > ALU_FID_SIZE) @@ -852,6 +1010,9 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, .port_fast_age = ksz_port_fast_age, + .port_vlan_filtering = lan937x_port_vlan_filtering, + .port_vlan_add = lan937x_port_vlan_add, + .port_vlan_del = lan937x_port_vlan_del, .port_fdb_dump = lan937x_port_fdb_dump, .port_fdb_add = lan937x_port_fdb_add, .port_fdb_del = lan937x_port_fdb_del,