From patchwork Tue Mar 22 19:54:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12788995 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1112BC433FE for ; Tue, 22 Mar 2022 19:55:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232051AbiCVT4p (ORCPT ); Tue, 22 Mar 2022 15:56:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53864 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231903AbiCVT4k (ORCPT ); Tue, 22 Mar 2022 15:56:40 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 157BC4D62A; Tue, 22 Mar 2022 12:55:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978912; x=1679514912; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uc/QWrMsi4Y5CzoHRYB83/Fr2NHNaFlU0o76Li4FnTM=; b=S260PG3LWGCpfKKu6bBggWB0BWZrl2LtmF0Fq1dBcg0HXRH3BMsRT8el vMKH6LbrxsbAyWGSJOBoTUaa10DsN4NyKofFnNuhCRnl0EPIDGqveUjEP 60aIObQ3m6pQ1xaSFNeC/Y/XBmF5hLOLNkmk8hyKliIq2u9CnH3FyQFA4 jyG6bqgxE2wkuQbJYxQi4/xn5SISTmeiWLVr4jyixjFxom58/sMus7lrM 1QSMQRVs+p5VKRaCaAX3xCPloiTCARIMyV7yRKVKcQhsEsj+rHaG2mbuQ bmh6Pzl0NWrRcRKvPD86WzOEPDecOkt8+WEumvloXnItv36iNetaQgKWN g==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="152878376" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:11 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) 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.2375.17; Tue, 22 Mar 2022 12:55:10 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:04 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 01/10] dt-bindings: net: make internal-delay-ps based on phy-mode Date: Wed, 23 Mar 2022 01:24:46 +0530 Message-ID: <20220322195455.703921-2-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 *-internal-delay-ps properties would be applicable only for RGMII interface modes. It is changed as per the request, https://lore.kernel.org/netdev/d8e5f6a8-a7e1-dabd-f4b4-ea8ea21d0a1d@gmail.com/ Ran dt_binding_check to confirm nothing is broken. Signed-off-by: Prasanna Vengateshan Reviewed-by: Andrew Lunn --- .../bindings/net/ethernet-controller.yaml | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml index 34c5463abcec..dc86a6479a86 100644 --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml @@ -123,12 +123,6 @@ properties: and is useful for determining certain configuration settings such as flow control thresholds. - rx-internal-delay-ps: - description: | - RGMII Receive Clock Delay defined in pico seconds. - This is used for controllers that have configurable RX internal delays. - If this property is present then the MAC applies the RX delay. - sfp: $ref: /schemas/types.yaml#/definitions/phandle description: @@ -140,12 +134,6 @@ properties: The size of the controller\'s transmit fifo in bytes. This is used for components that can have configurable fifo sizes. - tx-internal-delay-ps: - description: | - RGMII Transmit Clock Delay defined in pico seconds. - This is used for controllers that have configurable TX internal delays. - If this property is present then the MAC applies the TX delay. - managed: description: Specifies the PHY management type. If auto is set and fixed-link @@ -222,6 +210,31 @@ properties: required: - speed +allOf: + - if: + properties: + phy-mode: + contains: + enum: + - rgmii + - rgmii-rxid + - rgmii-txid + - rgmii-id + then: + properties: + rx-internal-delay-ps: + description: + RGMII Receive Clock Delay defined in pico seconds.This is + used for controllers that have configurable RX internal + delays. If this property is present then the MAC applies + the RX delay. + tx-internal-delay-ps: + description: + RGMII Transmit Clock Delay defined in pico seconds.This is + used for controllers that have configurable TX internal + delays. If this property is present then the MAC applies + the TX delay. + additionalProperties: true ... From patchwork Tue Mar 22 19:54:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12788996 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2480AC433EF for ; Tue, 22 Mar 2022 19:55:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232128AbiCVT4x (ORCPT ); Tue, 22 Mar 2022 15:56:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232062AbiCVT4w (ORCPT ); Tue, 22 Mar 2022 15:56:52 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 69ED44DF52; Tue, 22 Mar 2022 12:55:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978919; x=1679514919; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NnKSWRsw8QIx7UpcdyM5/vxOxc+dVCgzVMlIGo5Msg0=; b=ddjTyca+hqoEpT2GQpkUNuAE8vMlQkQbkiXDs4wbCI48KLkjDRD4segf iZ733TBENZeLi77/Fy4eVO0308kxR3/PnDk7gZyp6akakuUcYp45PijPm KHg42liavyIpq+cPT7N+ZCNk8QqIv99BTCc7UlIcS9B0J//26dHqublJi exZB25yuwfaQyJXTThwp4Z/6xvp6D2vkg/Mou2EmH9ioas2ltKk3JJX6n HXY5i0TcPW39+pX4q25hpV/QzCztykXbFSkK/dDCrfY5oTExdqP4rhH1p Wf26DF69OK0pskV/ulRjetGWOruYTOaIl2qS/n4Bx1ztjr6ao6TJPI46N g==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="152878388" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:18 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:17 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:11 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , , Rob Herring Subject: [PATCH v10 net-next 02/10] dt-bindings: net: dsa: dt bindings for microchip lan937x Date: Wed, 23 Mar 2022 01:24:47 +0530 Message-ID: <20220322195455.703921-3-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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. RGMII internal delay values for the mac is retrieved from rx-internal-delay-ps & tx-internal-delay-ps as per the feedback from v3 patch series. https://lore.kernel.org/netdev/20210802121550.gqgbipqdvp5x76ii@skbuf/ It supports only the delay value of 0ns and 2ns. Signed-off-by: Prasanna Vengateshan Reviewed-by: Rob Herring --- .../bindings/net/dsa/microchip,lan937x.yaml | 160 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 161 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..8974506d8f69 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml @@ -0,0 +1,160 @@ +# 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: + - UNGLinuxDriver@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 + + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + + tx-internal-delay-ps: + enum: [0, 2000] + default: 0 + + rx-internal-delay-ps: + enum: [0, 2000] + default: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + //Ethernet switch connected via spi to the host + ethernet { + #address-cells = <1>; + #size-cells = <0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + spi { + #address-cells = <1>; + #size-cells = <0>; + + 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"; + phy-mode = "internal"; + phy-handle = <&t1phy0>; + }; + port@1 { + reg = <1>; + label = "lan2"; + phy-mode = "internal"; + phy-handle = <&t1phy1>; + }; + port@2 { + reg = <2>; + label = "lan4"; + phy-mode = "internal"; + phy-handle = <&t1phy2>; + }; + port@3 { + reg = <3>; + label = "lan6"; + phy-mode = "internal"; + phy-handle = <&t1phy3>; + }; + port@4 { + reg = <4>; + phy-mode = "rgmii"; + ethernet = <ðernet>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + port@5 { + reg = <5>; + label = "lan7"; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + port@6 { + reg = <6>; + label = "lan5"; + phy-mode = "internal"; + phy-handle = <&t1phy6>; + }; + port@7 { + reg = <7>; + label = "lan3"; + phy-mode = "internal"; + phy-handle = <&t1phy7>; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + t1phy0: ethernet-phy@0{ + reg = <0x0>; + }; + t1phy1: ethernet-phy@1{ + reg = <0x1>; + }; + t1phy2: ethernet-phy@2{ + reg = <0x2>; + }; + t1phy3: ethernet-phy@3{ + reg = <0x3>; + }; + t1phy6: ethernet-phy@6{ + reg = <0x6>; + }; + t1phy7: ethernet-phy@7{ + reg = <0x7>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e5ce4f60786e..7d66f9f1679c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12664,6 +12664,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 Tue Mar 22 19:54:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12788997 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02439C4332F for ; Tue, 22 Mar 2022 19:55:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232179AbiCVT44 (ORCPT ); Tue, 22 Mar 2022 15:56:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232147AbiCVT4x (ORCPT ); Tue, 22 Mar 2022 15:56:53 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DA57D4EA22; Tue, 22 Mar 2022 12:55:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978925; x=1679514925; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2XZk/S9+NHNtKlWdz0v8OMI53RU+rLw5Jhy9KZMsm7o=; b=tQcjqip0SNfmxnERr/crULx4hKNm5buDgU1GA8GtTElHMIPCLXo/uuSp SaX14OGcy8n0cFUscYBsxFXUhJEvEB1S6X79cKuo19bDppKiNH23X4uMF 2vrxYcb8XUR23RpA9aq4sc2S0oWmH/TH7VGc9Tlo4Dihl7ZChB0xhZbg0 5m1Jh6Gi474W0/HSjmYprFT/GlPyfRZabWcE1r7qTyJGlaOlL7sQDFPDg zzwu1aoSgCE1UCUYqc6k2pt6ifa5/Fx4h2YcLXX15Kax7aDmJC468wTmY qL8K0pFG+iMaHAocUie6bO6PoKbAhHsuDv3qM854MiBM6pOshqNdL+4yl w==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="150041901" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:24 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:23 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:18 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 03/10] net: dsa: move mib->cnt_ptr reset code to ksz_common.c Date: Wed, 23 Mar 2022 01:24:48 +0530 Message-ID: <20220322195455.703921-4-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 mib->cnt_ptr resetting is handled in multiple places as part of port_init_cnt(). Hence moved mib->cnt_ptr code to ksz common layer and removed from individual product files. Signed-off-by: Prasanna Vengateshan Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- drivers/net/dsa/microchip/ksz8795.c | 2 -- drivers/net/dsa/microchip/ksz9477.c | 3 --- drivers/net/dsa/microchip/ksz_common.c | 8 +++++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index b2752978cb09..2da4e85e33b0 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -468,8 +468,6 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port) dropped, &mib->counters[mib->cnt_ptr]); ++mib->cnt_ptr; } - mib->cnt_ptr = 0; - memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); } static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 8222c8a6c5ec..346ce840f871 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -410,9 +410,6 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH); ksz_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)); } static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 8014b18d9391..36f8ed03f615 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -146,8 +146,14 @@ void ksz_init_mib_timer(struct ksz_device *dev) INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work); - for (i = 0; i < dev->port_cnt; i++) + for (i = 0; i < dev->port_cnt; i++) { + struct ksz_port_mib *mib = &dev->ports[i].mib; + dev->dev_ops->port_init_cnt(dev, i); + + mib->cnt_ptr = 0; + memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); + } } EXPORT_SYMBOL_GPL(ksz_init_mib_timer); From patchwork Tue Mar 22 19:54:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12788998 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9727AC433EF for ; Tue, 22 Mar 2022 19:55:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232230AbiCVT5J (ORCPT ); Tue, 22 Mar 2022 15:57:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232147AbiCVT5G (ORCPT ); Tue, 22 Mar 2022 15:57:06 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48FC74ECC2; Tue, 22 Mar 2022 12:55:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978931; x=1679514931; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gxt3DxyY1z81KkOe/lIClIVTOo3nLQhj12RS/hopOS8=; b=aF3Cu0bXTz+sx+T6YZm/agrjRf/eqtZ3phlPahpjrDJfjYylCLeiiXcU NsNj4n6NyQ1xFoyRGBYvAa9OBIxgt9KT2b8kxHzRWEx1rF89D2pQ6IuRm Dvu4/s+DH0NbnVRxTqwD9darBFIA6ttu4VSgNoA1FIH+KYiY8815m3ymA zR8YxlSARq5p1NU8j8gCZhMntAUkRP8P0RYFGItf8hjOgu2JbOi/Hw9WA wppGZSAf+9uWB5AwQvSkohhyerLaRlEBa3HGhKHOuZS4xfPotPyxnYe8e J+VKJB5UuYEFvlav2dErVXEXQBEp5JvP/FFU7C8LVHumDOPVSNfXqZc1p Q==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="150041911" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:31 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:30 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:24 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 04/10] net: dsa: tag_ksz: add tag handling for Microchip LAN937x Date: Wed, 23 Mar 2022 01:24:49 +0530 Message-ID: <20220322195455.703921-5-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 4 ++-- net/dsa/tag_ksz.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 934958fda962..e19da7c00ba0 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -53,6 +53,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_SJA1110_VALUE 23 #define DSA_TAG_PROTO_RTL8_4_VALUE 24 #define DSA_TAG_PROTO_RTL8_4T_VALUE 25 +#define DSA_TAG_PROTO_LAN937X_VALUE 26 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -81,6 +82,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_SJA1110 = DSA_TAG_PROTO_SJA1110_VALUE, DSA_TAG_PROTO_RTL8_4 = DSA_TAG_PROTO_RTL8_4_VALUE, DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE, + DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, }; struct dsa_switch; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 8cb87b5067ee..6d0414c9f7f4 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -87,10 +87,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/937x/9477/9893 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/937x/9477/9893 families of switches. config NET_DSA_TAG_OCELOT tristate "Tag driver for Ocelot family of switches, using NPI port" diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 3509fc967ca9..38fa19c1e2d5 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -193,10 +193,69 @@ 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 xmit, 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 rcv, 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_EGRESS_TAG_LEN 2 + +#define LAN937X_TAIL_TAG_BLOCKING_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); + const struct ethhdr *hdr = eth_hdr(skb); + __be16 *tag; + u16 val; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + return NULL; + + tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN); + + val = BIT(dp->index); + + if (is_link_local_ether_addr(hdr->h_dest)) + val |= LAN937X_TAIL_TAG_BLOCKING_OVERRIDE; + + /* Tail tag valid bit - This bit should always be set by the CPU */ + val |= LAN937X_TAIL_TAG_VALID; + + put_unaligned_be16(val, tag); + + return skb; +} + +static const struct dsa_device_ops lan937x_netdev_ops = { + .name = "lan937x", + .proto = DSA_TAG_PROTO_LAN937X, + .xmit = lan937x_xmit, + .rcv = ksz9477_rcv, + .needed_tailroom = LAN937X_EGRESS_TAG_LEN, +}; + +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 Tue Mar 22 19:54:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12789003 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6520EC433F5 for ; Tue, 22 Mar 2022 19:56:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232130AbiCVT6P (ORCPT ); Tue, 22 Mar 2022 15:58:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232314AbiCVT5J (ORCPT ); Tue, 22 Mar 2022 15:57:09 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57ED74E38E; Tue, 22 Mar 2022 12:55:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978938; x=1679514938; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=i1++A7ed97JwmSPdwGApmKyvZ7oeMGuygZ3Igfx7w4c=; b=T3evkT4reWhbJnnbRrXwKVAm07CoIlI3rPBVgdXyE0o3OmFaupTn8mPV RpLEvPArHaq381l0Bx5pMeIHJesrB6OVAo3ivbSioFNqNtHRomdTdhyey wb8uSLonTvbdwsLj/fMNo9Y0AQHZ9fmDBbOH3RhzbRnMaF4cNcLQG62RL tsTkQsjfYkHNs3BYzLNFlb7ejONomICe3mPAjhBV1Qqgvtkk01vdmoRBd 2AuotZIJh45XEP3DXHNWh/T3tdsxa4IIJHS7Bpo5Av1cdlE1u2TtIyPmC 2okF9oWd8d50szlHk4jYvzHp5nEVCaxrh9ekZFih/sGhi3og+qslbMHzv g==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="89775119" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:36 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:36 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:30 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 05/10] net: dsa: microchip: add DSA support for microchip lan937x Date: Wed, 23 Mar 2022 01:24:50 +0530 Message-ID: <20220322195455.703921-6-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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. RGMII internal delay values for the mac is retrieved from rx-internal-delay-ps & tx-internal-delay-ps as per the feedback from v3 patch series. https://lore.kernel.org/netdev/20210802121550.gqgbipqdvp5x76ii@skbuf/ It supports standard delay 2ns only. If the property is not found, the value will be forced to 0. Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/Kconfig | 12 + drivers/net/dsa/microchip/Makefile | 5 + drivers/net/dsa/microchip/ksz_common.h | 5 + drivers/net/dsa/microchip/lan937x_dev.c | 631 +++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 117 ++++ drivers/net/dsa/microchip/lan937x_main.c | 320 +++++++++++ drivers/net/dsa/microchip/lan937x_reg.h | 688 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_spi.c | 236 ++++++++ 8 files changed, 2014 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 c9e2a8989556..f329cca934ee 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 2a03b21a3386..28d8eb62a795 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -6,3 +6,8 @@ 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_KSZ8863_SMI) += ksz8863_smi.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 485d4a948c38..372170571088 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -42,6 +42,8 @@ struct ksz_port { struct ksz_port_mib mib; phy_interface_t interface; u16 max_frame; + u32 rgmii_tx_val; + u32 rgmii_rx_val; }; struct ksz_device { @@ -148,6 +150,9 @@ void ksz_switch_remove(struct ksz_device *dev); int ksz8_switch_register(struct ksz_device *dev); int ksz9477_switch_register(struct ksz_device *dev); +int lan937x_switch_register(struct ksz_device *dev); + +int lan937x_check_device_id(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..784a24d0aa08 --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip lan937x dev ops functions + * Copyright (C) 2019-2021 Microchip Technology Inc. + */ +#include +#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" }, +}; + +int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +int lan937x_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, + bool set) +{ + return regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); +} + +int lan937x_pread8(struct ksz_device *dev, int port, int offset, u8 *data) +{ + return ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +int lan937x_pread16(struct ksz_device *dev, int port, int offset, u16 *data) +{ + return ksz_read16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +int lan937x_pread32(struct ksz_device *dev, int port, int offset, u32 *data) +{ + return ksz_read32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +int lan937x_pwrite8(struct ksz_device *dev, int port, int offset, u8 data) +{ + return ksz_write8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +int lan937x_pwrite16(struct ksz_device *dev, int port, int offset, u16 data) +{ + return ksz_write16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +int lan937x_pwrite32(struct ksz_device *dev, int port, int offset, u32 data) +{ + return ksz_write32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +void lan937x_cfg_port_member(struct ksz_device *dev, int port, u8 member) +{ + lan937x_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, 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_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, data); + + ret = regmap_read_poll_timeout(dev->regmap[2], + PORT_CTRL_ADDR(port, + REG_PORT_MIB_CTRL_STAT), + val, !(val & MIB_COUNTER_READ), + 10, 1000); + 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; +} + +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_r_mib_stats64(struct ksz_device *dev, int port) +{ + struct ksz_port_mib *mib = &dev->ports[port].mib; + struct rtnl_link_stats64 *s; + u64 *ctr = mib->counters; + + s = &mib->stats64; + spin_lock(&mib->stats64_lock); + + s->rx_packets = ctr[lan937x_mib_rx_mcast] + + ctr[lan937x_mib_rx_bcast] + + ctr[lan937x_mib_rx_ucast] + + ctr[lan937x_mib_rx_pause]; + + s->tx_packets = ctr[lan937x_mib_tx_mcast] + + ctr[lan937x_mib_tx_bcast] + + ctr[lan937x_mib_tx_ucast] + + ctr[lan937x_mib_tx_pause]; + + s->rx_bytes = ctr[lan937x_mib_rx_total]; + s->tx_bytes = ctr[lan937x_mib_tx_total]; + + s->rx_errors = ctr[lan937x_mib_rx_fragments] + + ctr[lan937x_mib_rx_jabbers] + + ctr[lan937x_mib_rx_sym_err] + + ctr[lan937x_mib_rx_align_err] + + ctr[lan937x_mib_rx_crc_err]; + + s->tx_errors = ctr[lan937x_mib_tx_exc_col] + + ctr[lan937x_mib_tx_late_col]; + + s->rx_dropped = ctr[lan937x_mib_rx_discard]; + s->tx_dropped = ctr[lan937x_mib_tx_discard]; + s->multicast = ctr[lan937x_mib_rx_mcast]; + + s->collisions = ctr[lan937x_mib_tx_late_col] + + ctr[lan937x_mib_tx_single_col] + + ctr[lan937x_mib_tx_mult_col]; + + s->rx_length_errors = ctr[lan937x_mib_rx_fragments] + + ctr[lan937x_mib_rx_jabbers]; + + s->rx_crc_errors = ctr[lan937x_mib_rx_crc_err]; + s->rx_frame_errors = ctr[lan937x_mib_rx_align_err]; + s->tx_aborted_errors = ctr[lan937x_mib_tx_exc_col]; + s->tx_window_errors = ctr[lan937x_mib_tx_late_col]; + + spin_unlock(&mib->stats64_lock); +} + +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, + 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, 0); + mutex_unlock(&mib->cnt_mutex); +} + +int lan937x_reset_switch(struct ksz_device *dev) +{ + u32 data32; + u8 data8; + int ret; + + /* reset switch */ + ret = lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true); + if (ret < 0) + return ret; + + ret = ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + if (ret < 0) + return ret; + + /* Enable Auto Aging */ + ret = ksz_write8(dev, REG_SW_LUE_CTRL_1, data8 | SW_LINK_AUTO_AGING); + if (ret < 0) + return ret; + + /* disable interrupts */ + ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); + if (ret < 0) + return ret; + + ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF); + if (ret < 0) + return ret; + + return ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); +} + +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 < 0) + return ret; + + if (id32 != 0 && id32 != 0xffffffff) { + 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); +} + +int lan937x_enable_spi_indirect_access(struct ksz_device *dev) +{ + u16 data16; + u8 data8; + int ret; + + ret = ksz_read8(dev, REG_GLOBAL_CTRL_0, &data8); + if (ret < 0) + return ret; + + /* Check if PHY register is blocked */ + if (data8 & SW_PHY_REG_BLOCK) { + /* Enable Phy access through SPI */ + data8 &= ~SW_PHY_REG_BLOCK; + + ret = ksz_write8(dev, REG_GLOBAL_CTRL_0, data8); + if (ret < 0) + return ret; + } + + ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16); + if (ret < 0) + return ret; + + /* Allow SPI access */ + data16 |= VPHY_SPI_INDIRECT_ENABLE; + + return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16); +} + +static u32 lan937x_get_port_addr(int port, int offset) +{ + return PORT_CTRL_ADDR(port, offset); +} + +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; +} + +bool lan937x_is_rgmii_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 true; + + return false; +} + +bool lan937x_is_internal_base_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_base_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_base_tx_phy_port(dev, port)) + return true; + + return false; +} + +static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg) +{ + u16 temp, addr_base; + + if (lan937x_is_internal_base_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))); + + return ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp); +} + +int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg, + u16 val) +{ + unsigned int value; + int ret; + + /* Check for internal phy port */ + if (!lan937x_is_internal_phy_port(dev, addr)) + return -EOPNOTSUPP; + + ret = lan937x_vphy_ind_addr_wr(dev, addr, reg); + if (ret < 0) + return ret; + + /* Write the data to be written to the VPHY reg */ + ret = ksz_write16(dev, REG_VPHY_IND_DATA__2, val); + if (ret < 0) + return ret; + + /* Write the Write En and Busy bit */ + ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, + (VPHY_IND_WRITE | VPHY_IND_BUSY)); + if (ret < 0) + return ret; + + ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2, + value, !(value & VPHY_IND_BUSY), 10, + 1000); + if (ret < 0) { + dev_err(dev->dev, "Failed to write phy register\n"); + return ret; + } + + return 0; +} + +int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, + u16 *val) +{ + unsigned int value; + int ret; + + /* Check for internal phy port, return 0xffff for non-existent phy */ + if (!lan937x_is_internal_phy_port(dev, addr)) + return 0xffff; + + ret = lan937x_vphy_ind_addr_wr(dev, addr, reg); + if (ret < 0) + return ret; + + /* Write Read and Busy bit to start the transaction */ + ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY); + if (ret < 0) + return ret; + + ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2, + value, !(value & VPHY_IND_BUSY), 10, + 1000); + if (ret < 0) { + dev_err(dev->dev, "Failed to read phy register\n"); + return ret; + } + + /* Read the VPHY register which has the PHY data */ + return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); +} + +void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) +{ + struct dsa_switch *ds = dev->ds; + u8 member; + + /* enable tag tail for host port */ + if (cpu_port) + lan937x_port_cfg(dev, port, REG_PORT_CTRL_0, + PORT_TAIL_TAG_ENABLE, true); + + /* disable frame check length field */ + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_FR_CHK_LENGTH, + false); + + /* set back pressure for half duplex */ + lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, + true); + + /* enable 802.1p priority */ + lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); + + if (!lan937x_is_internal_phy_port(dev, port)) + lan937x_port_cfg(dev, port, REG_PORT_XMII_CTRL_0, + PORT_TX_FLOW_CTRL | PORT_RX_FLOW_CTRL, + true); + + if (cpu_port) + member = dsa_user_ports(ds); + else + member = BIT(dsa_upstream_port(ds, port)); + + lan937x_cfg_port_member(dev, port, member); +} + +static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct ksz_device *dev = bus->priv; + u16 val; + int ret; + + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + + ret = lan937x_internal_phy_read(dev, addr, regnum, &val); + if (ret < 0) + return ret; + + return val; +} + +static int lan937x_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct ksz_device *dev = bus->priv; + + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + + return lan937x_internal_phy_write(dev, addr, regnum, val); +} + +static int lan937x_mdio_register(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + struct device_node *mdio_np; + struct mii_bus *bus; + int ret; + + mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); + if (!mdio_np) { + dev_err(ds->dev, "no MDIO bus node\n"); + return -ENODEV; + } + + bus = devm_mdiobus_alloc(ds->dev); + if (!bus) { + of_node_put(mdio_np); + return -ENOMEM; + } + + bus->priv = dev; + bus->read = lan937x_sw_mdio_read; + bus->write = lan937x_sw_mdio_write; + bus->name = "lan937x slave smi"; + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + bus->parent = ds->dev; + bus->phy_mask = ~ds->phys_mii_mask; + + ds->slave_mii_bus = bus; + + ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); + if (ret) { + dev_err(ds->dev, "unable to register MDIO bus %s\n", + bus->id); + } + + of_node_put(mdio_np); + + return ret; +} + +static int lan937x_switch_init(struct ksz_device *dev) +{ + int i, ret; + + dev->ds->ops = &lan937x_switch_ops; + + /* Check device tree */ + ret = lan937x_check_device_id(dev); + if (ret < 0) + return ret; + + 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++) { + spin_lock_init(&dev->ports[i].mib.stats64_lock); + 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; +} + +static int lan937x_init(struct ksz_device *dev) +{ + int ret; + + ret = lan937x_switch_init(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to initialize the switch"); + return ret; + } + + /* enable Indirect Access from SPI to the VPHY registers */ + ret = lan937x_enable_spi_indirect_access(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to enable spi indirect access"); + return ret; + } + + ret = lan937x_mdio_register(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to register the mdio"); + return ret; + } + + 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, + .r_mib_cnt = lan937x_r_mib_cnt, + .r_mib_pkt = lan937x_r_mib_pkt, + .port_init_cnt = lan937x_port_init_cnt, + .r_mib_stat64 = lan937x_r_mib_stats64, + .shutdown = lan937x_reset_switch, + .detect = lan937x_switch_detect, + .init = lan937x_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..eba36912969a --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip lan937x dev ops headers + * Copyright (C) 2019-2021 Microchip Technology Inc. + */ + +#ifndef __LAN937X_CFG_H +#define __LAN937X_CFG_H + +int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set); +int lan937x_port_cfg(struct ksz_device *dev, int port, int offset, + u8 bits, bool set); +int lan937x_pread8(struct ksz_device *dev, int port, int offset, + u8 *data); +int lan937x_pread16(struct ksz_device *dev, int port, int offset, + u16 *data); +int lan937x_pread32(struct ksz_device *dev, int port, int offset, + u32 *data); +int lan937x_pwrite8(struct ksz_device *dev, int port, + int offset, u8 data); +int lan937x_pwrite16(struct ksz_device *dev, int port, + int offset, u16 data); +int lan937x_pwrite32(struct ksz_device *dev, int port, + int offset, u32 data); +int lan937x_internal_phy_write(struct ksz_device *dev, int addr, + int reg, u16 val); +int lan937x_internal_phy_read(struct ksz_device *dev, int addr, + int reg, u16 *val); +bool lan937x_is_internal_phy_port(struct ksz_device *dev, int port); +bool lan937x_is_internal_base_tx_phy_port(struct ksz_device *dev, int port); +bool lan937x_is_internal_base_t1_phy_port(struct ksz_device *dev, int port); +bool lan937x_is_rgmii_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_enable_spi_indirect_access(struct ksz_device *dev); +void lan937x_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, + u64 *dropped, u64 *cnt); + +struct mib_names { + int index; + char string[ETH_GSTRING_LEN]; +}; + +enum lan937x_mib_list { + lan937x_mib_rx_hi_pri_byte = 0, + lan937x_mib_rx_undersize, + lan937x_mib_rx_fragments, + lan937x_mib_rx_oversize, + lan937x_mib_rx_jabbers, + lan937x_mib_rx_sym_err, + lan937x_mib_rx_crc_err, + lan937x_mib_rx_align_err, + lan937x_mib_rx_mac_ctrl, + lan937x_mib_rx_pause, + lan937x_mib_rx_bcast, + lan937x_mib_rx_mcast, + lan937x_mib_rx_ucast, + lan937x_mib_rx_64_or_less, + lan937x_mib_rx_65_127, + lan937x_mib_rx_128_255, + lan937x_mib_rx_256_511, + lan937x_mib_rx_512_1023, + lan937x_mib_rx_1024_1522, + lan937x_mib_rx_1523_2000, + lan937x_mib_rx_2001, + lan937x_mib_tx_hi_pri_byte, + lan937x_mib_tx_late_col, + lan937x_mib_tx_pause, + lan937x_mib_tx_bcast, + lan937x_mib_tx_mcast, + lan937x_mib_tx_ucast, + lan937x_mib_tx_deferred, + lan937x_mib_tx_total_col, + lan937x_mib_tx_exc_col, + lan937x_mib_tx_single_col, + lan937x_mib_tx_mult_col, + lan937x_mib_rx_total, + lan937x_mib_tx_total, + lan937x_mib_rx_discard, + lan937x_mib_tx_discard, +}; + +struct lan_alu_struct { + /* entry 1 */ + u32 is_static:1; + u32 is_src_filter:1; + u32 is_dst_filter:1; + u32 prio_age:3; + u32 _reserv_0_1:23; + u32 mstp:3; + /* entry 2 */ + u32 is_override:1; + u32 is_use_fid:1; + u32 _reserv_1_1:22; + u32 port_forward:8; + /* entry 3 & 4*/ + u32 _reserv_2_1:9; + u32 fid:7; + u8 mac[ETH_ALEN]; +}; + +struct lan937x_vlan { + /* entry 1 */ + bool valid; + u8 fid; + /* entry 2 */ + u32 untag_prtmap; + /* entry 3 */ + u32 fwd_map; +}; + +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..b5164be297c8 --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip LAN937X switch driver main logic + * Copyright (C) 2019-2021 Microchip Technology Inc. + */ +#include +#include +#include +#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_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val; + int ret; + + ret = lan937x_internal_phy_read(dev, addr, reg, &val); + if (ret < 0) + return ret; + + 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_internal_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; + 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; + break; + case BR_STATE_LISTENING: + data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); + break; + case BR_STATE_LEARNING: + data |= PORT_RX_ENABLE; + break; + case BR_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + break; + case BR_STATE_BLOCKING: + data |= PORT_LEARN_DISABLE; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + lan937x_pwrite8(dev, port, P_STP_CTRL, data); + + p = &dev->ports[port]; + p->stp_state = state; + + ksz_update_port_member(dev, port); +} + +static void lan937x_config_cpu_port(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + 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))) { + dev->cpu_port = i; + + /* enable cpu port */ + lan937x_port_setup(dev, i, true); + } + } + + for (i = 0; i < dev->port_cnt; i++) { + if (i == dev->cpu_port) + continue; + + lan937x_port_stp_state_set(ds, i, BR_STATE_DISABLED); + } +} + +static int lan937x_set_rgmii_delay(struct ksz_device *dev, int port, + u32 val, bool is_tx) +{ + struct ksz_port *p = &dev->ports[port]; + const char *name[2] = { "rx", "tx" }; + + /* alert if delay is out of range */ + if (val != 0 && val != 2000) { + dev_err(dev->dev, + "rgmii %s delay %d is out of range for the port %d\n", + name[is_tx], val, port); + return -EOPNOTSUPP; + } + + /* get the valid value & store it for delay calculation */ + if (is_tx) + p->rgmii_tx_val = val; + else + p->rgmii_rx_val = val; + + return 0; +} + +static int lan937x_parse_dt_rgmii_delay(struct ksz_device *dev) +{ + struct device_node *ports, *port; + int err, p; + u32 val; + + ports = of_get_child_by_name(dev->dev->of_node, "ports"); + if (!ports) + ports = of_get_child_by_name(dev->dev->of_node, + "ethernet-ports"); + if (!ports) { + dev_err(dev->dev, "no ports child node found\n"); + return -EINVAL; + } + + for_each_available_child_of_node(ports, port) { + err = of_property_read_u32(port, "reg", &p); + if (err) { + dev_err(dev->dev, "Port num not defined in the DT, \"reg\" property\n"); + of_node_put(ports); + of_node_put(port); + return err; + } + + /* skip for internal ports */ + if (lan937x_is_internal_phy_port(dev, p)) + continue; + + if (of_property_read_u32(port, "rx-internal-delay-ps", &val)) + val = 0; + + err = lan937x_set_rgmii_delay(dev, p, val, false); + if (err) + break; + + if (of_property_read_u32(port, "tx-internal-delay-ps", &val)) + val = 0; + + err = lan937x_set_rgmii_delay(dev, p, val, true); + if (err) + break; + } + + of_node_put(ports); + return err; +} + +static int lan937x_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + u32 data32; + u8 data8; + int ret; + + ret = lan937x_reset_switch(dev); + if (ret < 0) + return ret; + + ret = ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + if (ret < 0) + return ret; + + /* Enable Auto Aging */ + ret = ksz_write8(dev, REG_SW_LUE_CTRL_1, data8 | SW_LINK_AUTO_AGING); + if (ret < 0) + return ret; + + /* disable interrupts */ + ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); + if (ret < 0) + return ret; + + ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF); + if (ret < 0) + return ret; + + /* Read interrupt status register */ + ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); + if (ret < 0) + return ret; + + /* Apply rgmii internal delay for the mac based on device tree */ + ret = lan937x_parse_dt_rgmii_delay(dev); + if (ret < 0) + return ret; + + /* The VLAN aware is a global setting. Mixed vlan + * filterings are not supported. + */ + ds->vlan_filtering_is_global = true; + + /* Configure cpu port */ + lan937x_config_cpu_port(ds); + + /* Enable aggressive back off for half duplex & UNH mode */ + lan937x_cfg(dev, REG_SW_MAC_CTRL_0, + (SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF | SW_AGGR_BACKOFF), + true); + + /* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop + * packets when 16 or more collisions occur + */ + lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, true); + + /* Enable reserved multicast table */ + 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); + + /* disable CLK125 & CLK25, 1: disable, 0: enable */ + lan937x_cfg(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, + (SW_CLK125_ENB | SW_CLK25_ENB), true); + + 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 new_mtu) +{ + struct ksz_device *dev = ds->priv; + int ret; + + new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN; + + if (dsa_is_cpu_port(ds, port)) + new_mtu += LAN937X_TAG_LEN; + + if (new_mtu >= FR_MIN_SIZE) + ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, + PORT_JUMBO_EN, true); + else + ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, + PORT_JUMBO_EN, false); + if (ret < 0) { + dev_err(ds->dev, "failed to enable jumbo\n"); + return ret; + } + + /* Write the frame size in PORT_MAX_FR_SIZE register */ + ret = lan937x_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu); + if (ret < 0) { + dev_err(ds->dev, "failed to change the mtu\n"); + return ret; + } + + return 0; +} + +static int lan937x_get_max_mtu(struct dsa_switch *ds, int port) +{ + /* Frame max 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 - VLAN_ETH_HLEN - ETH_FCS_LEN); +} + +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..d0de595f6c4e --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -0,0 +1,688 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip LAN937X switch register definitions + * Copyright (C) 2019-2021 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_CLK125_ENB BIT(1) +#define SW_CLK25_ENB 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_FLUSH_STP_TABLE BIT(5) +#define SW_FLUSH_MSTP_TABLE BIT(4) +#define SW_SRC_ADDR_FILTER 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 BR_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 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_CTRL_BASE 0x0100 +#define REG_PORT_TX_PHY_CTRL_BASE 0x0280 +#define REG_TX_PHY_CTRL_BASE 0x0980 + +#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_3 0x0303 +#define PORT_DUPLEX_STATUS_FULL BIT(3) + +#define REG_PORT_XMII_CTRL_4 0x0304 +#define PORT_TX_TUNE_ADJ 0x3F80 + +#define REG_PORT_XMII_CTRL_5 0x0306 +#define PORT_DLL_RESET BIT(15) +#define PORT_RX_TUNE_ADJ 0x3F80 + +#define PORT_TUNE_ADJ 0x3F80 + +/* 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 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_CTL0 0x0B0E +#define REG_PORT_LUE_UNK_CTL1 0x0B10 +#define REG_PORT_LUE_UNK_VID_CTRL__2 0x0B12 + +#define PORT_UNK_UCAST_MCAST_ENABLE BIT(15) +#define PORT_UCAST_MCAST_MASK 0xFF +#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 BR_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_FULL_DUPLEX BIT(6) +#define PORT_TX_FLOW_CTRL BIT(5) +#define PORT_RX_FLOW_CTRL BIT(3) +#define PORT_MAC_SPEED_100 BIT(4) + +#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 BR_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) +#define LAN937X_TAG_LEN 2 + +#define RGMII_1_TX_DELAY_2NS 2 +#define RGMII_2_TX_DELAY_2NS 0 +#define RGMII_1_RX_DELAY_2NS 0x1B +#define RGMII_2_RX_DELAY_2NS 0x14 + +#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..a50dfcf27aff --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_spi.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip LAN937X switch driver register access through SPI + * Copyright (C) 2019-2021 Microchip Technology Inc. + */ +#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); + +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; +}; + +static const struct of_device_id lan937x_dt_ids[]; + +static const struct lan937x_chip_data lan937x_switch_chips[] = { + { + .chip_id = 0x00937010, + .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 = 0x00937110, + .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 = 0x00937210, + .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 = 0x00937310, + .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 = 0x00937410, + .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, + }, +}; + +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; +} + +int lan937x_check_device_id(struct ksz_device *dev) +{ + const struct lan937x_chip_data *dt_chip_data; + const struct of_device_id *match; + int i; + + dt_chip_data = of_device_get_match_data(dev->dev); + + if (!dt_chip_data) + return -EINVAL; + + for (match = lan937x_dt_ids; match->compatible[0]; match++) { + const struct lan937x_chip_data *chip_data = match->data; + + /* Check for chip id */ + if (chip_data->chip_id != dev->chip_id) + continue; + + /* Check for Device Tree and Chip ID */ + if (dt_chip_data->chip_id != dev->chip_id) { + dev_err(dev->dev, + "Device tree specifies chip %s but found %s, please fix it!\n", + dt_chip_data->dev_name, chip_data->dev_name); + return -ENODEV; + } + + break; + } + + 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; + + return 0; +} +EXPORT_SYMBOL(lan937x_check_device_id); + +static void lan937x_spi_remove(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev) + ksz_switch_remove(dev); + + spi_set_drvdata(spi, NULL); +} + +static void lan937x_spi_shutdown(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev) + dsa_switch_shutdown(dev->ds); + + spi_set_drvdata(spi, NULL); +} + +static const struct of_device_id lan937x_dt_ids[] = { + { .compatible = "microchip,lan9370", .data = &lan937x_switch_chips[0] }, + { .compatible = "microchip,lan9371", .data = &lan937x_switch_chips[1] }, + { .compatible = "microchip,lan9372", .data = &lan937x_switch_chips[2] }, + { .compatible = "microchip,lan9373", .data = &lan937x_switch_chips[3] }, + { .compatible = "microchip,lan9374", .data = &lan937x_switch_chips[4] }, + {}, +}; +MODULE_DEVICE_TABLE(of, lan937x_dt_ids); + +static const struct spi_device_id lan937x_spi_ids[] = { + { .name = "lan9370" }, + { .name = "lan9371" }, + { .name = "lan9372" }, + { .name = "lan9373" }, + { .name = "lan9374" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, lan937x_spi_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, + .id_table = lan937x_spi_ids, +}; + +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 Tue Mar 22 19:54:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12788999 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0693FC433F5 for ; Tue, 22 Mar 2022 19:55:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232418AbiCVT5X (ORCPT ); Tue, 22 Mar 2022 15:57:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232147AbiCVT5M (ORCPT ); Tue, 22 Mar 2022 15:57:12 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AFF0A4D9E8; Tue, 22 Mar 2022 12:55:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978943; x=1679514943; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HeXobi3Uy+VITO3vDI5dl1U/DYm0aref8Da7pvzBMkE=; b=CiusE8f7Ms8HFHqH56Bma10GJ5QQHUwJ9ORN1znX9IVCMlBzVwhwcqLk lxkhumTGtQKv1sNG5JtH6l0nzY2Jz7Ex9JyaqzpSdYUkcpq5s0aBPmKCU HDpQPZX+69sWQ5EEf6DPNhEy9qJmejvTG4bVR1+wleR4A8Xgobb4GORMr 25aNh0hzR1Z74QAavCQY8rM8v2zHsbDqEfIO/brwa2KttFWOkzaMG8lqJ eysSxXtm1kPg/Bke9v8EOv6HOwiJWzNso5fqe3PUckQ11KK1seUQfF+Ja WiWPEMfI42geyus/6YqtaHoacGzg7Me9lDbPNSUxLNlC2mDiu4VYa6ks+ Q==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="166737703" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:42 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:42 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:36 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 06/10] net: dsa: microchip: add support for phylink management Date: Wed, 23 Mar 2022 01:24:51 +0530 Message-ID: <20220322195455.703921-7-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 phylink_get_caps() is implemented and reused KSZ commmon API for phylink_mac_link_down() operation lan937x_phylink_mac_config configures the interface using lan937x_mac_config and lan937x_phylink_mac_link_up configures the speed/duplex/flow control. Currently SGMII & in-band neg are not supported & it will be added later. Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_dev.c | 158 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 5 + drivers/net/dsa/microchip/lan937x_main.c | 66 ++++++++++ 3 files changed, 229 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c index 784a24d0aa08..dfd93fa49939 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.c +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -449,6 +449,164 @@ int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); } +static void lan937x_config_gbit(struct ksz_device *dev, bool gbit, u8 *data) +{ + if (gbit) + *data &= ~PORT_MII_NOT_1GBIT; + else + *data |= PORT_MII_NOT_1GBIT; +} + +static void lan937x_update_rgmii_tx_rx_delay(struct ksz_device *dev, int port, + bool is_tx) +{ + u16 data16; + int reg; + u8 val; + + /* Apply different codes based on the ports as per characterization + * results + */ + if (is_tx) { + reg = REG_PORT_XMII_CTRL_5; + val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS : + RGMII_2_TX_DELAY_2NS; + } else { + reg = REG_PORT_XMII_CTRL_4; + val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS : + RGMII_2_RX_DELAY_2NS; + } + + lan937x_pread16(dev, port, reg, &data16); + + /* clear tune Adjust */ + data16 &= ~PORT_TUNE_ADJ; + data16 |= (val << 7); + lan937x_pwrite16(dev, port, reg, data16); + + data16 |= PORT_DLL_RESET; + /* write DLL reset to take effect */ + lan937x_pwrite16(dev, port, reg, data16); +} + +static void lan937x_apply_rgmii_delay(struct ksz_device *dev, int port, + phy_interface_t interface, u8 val) +{ + struct ksz_port *p = &dev->ports[port]; + + /* Clear Ingress & Egress internal delay enabled bits */ + val &= ~(PORT_RGMII_ID_EG_ENABLE | PORT_RGMII_ID_IG_ENABLE); + + /* if the delay is 0, do not enable DLL */ + if (p->rgmii_tx_val) { + lan937x_update_rgmii_tx_rx_delay(dev, port, true); + dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n", + port); + val |= PORT_RGMII_ID_EG_ENABLE; + } + + /* if the delay is 0, do not enable DLL */ + if (p->rgmii_rx_val) { + lan937x_update_rgmii_tx_rx_delay(dev, port, false); + dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n", + port); + val |= PORT_RGMII_ID_IG_ENABLE; + } + + /* Enable RGMII internal delays */ + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, val); +} + +void lan937x_mac_config(struct ksz_device *dev, int port, + phy_interface_t interface) +{ + u8 data8; + + 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 interface */ + switch (interface) { + case PHY_INTERFACE_MODE_MII: + lan937x_config_gbit(dev, false, &data8); + data8 |= PORT_MII_SEL; + break; + case PHY_INTERFACE_MODE_RMII: + lan937x_config_gbit(dev, false, &data8); + data8 |= PORT_RMII_SEL; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + lan937x_config_gbit(dev, true, &data8); + data8 |= PORT_RGMII_SEL; + + /* Apply rgmii internal delay for the mac */ + lan937x_apply_rgmii_delay(dev, port, interface, data8); + + /* rgmii delay configuration is already applied above, + * hence return from here as no changes required + */ + return; + default: + dev_err(dev->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(interface), port); + return; + } + + /* Write the updated value */ + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); +} + +void lan937x_config_interface(struct ksz_device *dev, int port, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + u8 xmii_ctrl0, xmii_ctrl1; + + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_0, &xmii_ctrl0); + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &xmii_ctrl1); + + switch (speed) { + case SPEED_1000: + lan937x_config_gbit(dev, true, &xmii_ctrl1); + break; + case SPEED_100: + lan937x_config_gbit(dev, false, &xmii_ctrl1); + xmii_ctrl0 |= PORT_MAC_SPEED_100; + break; + case SPEED_10: + lan937x_config_gbit(dev, false, &xmii_ctrl1); + xmii_ctrl0 &= ~PORT_MAC_SPEED_100; + break; + default: + dev_err(dev->dev, "Unsupported speed on port %d: %d\n", + port, speed); + return; + } + + if (duplex) + xmii_ctrl0 |= PORT_FULL_DUPLEX; + else + xmii_ctrl0 &= ~PORT_FULL_DUPLEX; + + if (tx_pause) + xmii_ctrl0 |= PORT_TX_FLOW_CTRL; + else + xmii_ctrl1 &= ~PORT_TX_FLOW_CTRL; + + if (rx_pause) + xmii_ctrl0 |= PORT_RX_FLOW_CTRL; + else + xmii_ctrl0 &= ~PORT_RX_FLOW_CTRL; + + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_0, xmii_ctrl0); + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, xmii_ctrl1); +} + void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) { struct dsa_switch *ds = dev->ds; diff --git a/drivers/net/dsa/microchip/lan937x_dev.h b/drivers/net/dsa/microchip/lan937x_dev.h index eba36912969a..a9b435594634 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.h +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -34,6 +34,11 @@ 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_enable_spi_indirect_access(struct ksz_device *dev); +void lan937x_config_interface(struct ksz_device *dev, int port, + int speed, int duplex, + bool tx_pause, bool rx_pause); +void lan937x_mac_config(struct ksz_device *dev, int port, + phy_interface_t interface); void lan937x_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, u64 *dropped, u64 *cnt); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index b5164be297c8..c7b7b9b373d7 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -295,6 +295,68 @@ static int lan937x_get_max_mtu(struct dsa_switch *ds, int port) return (FR_MAX_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN); } +static void lan937x_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct ksz_device *dev = ds->priv; + + /* Internal PHYs */ + if (lan937x_is_internal_phy_port(dev, port)) + return; + + if (phylink_autoneg_inband(mode)) { + dev_err(ds->dev, "In-band AN not supported!\n"); + return; + } + + lan937x_mac_config(dev, port, state->interface); +} + +static void lan937x_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct ksz_device *dev = ds->priv; + + /* Internal PHYs */ + if (lan937x_is_internal_phy_port(dev, port)) + return; + + lan937x_config_interface(dev, port, speed, duplex, + tx_pause, rx_pause); +} + +static void lan937x_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) +{ + struct ksz_device *dev = ds->priv; + + /* non legacy driver */ + config->legacy_pre_march2020 = false; + + config->mac_capabilities = MAC_100FD; + + /* internal T1 PHY */ + if (lan937x_is_internal_base_t1_phy_port(dev, port)) { + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + } else if (lan937x_is_rgmii_port(dev, port)) { + /* MII/RMII/RGMII ports */ + config->mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_100HD | MAC_10 | MAC_1000FD; + phy_interface_set_rgmii(config->supported_interfaces); + + __set_bit(PHY_INTERFACE_MODE_MII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RMII, + config->supported_interfaces); + } +} + const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .setup = lan937x_setup, @@ -307,6 +369,10 @@ 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_get_caps = lan937x_phylink_get_caps, + .phylink_mac_link_down = ksz_mac_link_down, + .phylink_mac_config = lan937x_phylink_mac_config, + .phylink_mac_link_up = lan937x_phylink_mac_link_up, }; int lan937x_switch_register(struct ksz_device *dev) From patchwork Tue Mar 22 19:54:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12789000 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F2D5EC433F5 for ; Tue, 22 Mar 2022 19:55:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232495AbiCVT5Z (ORCPT ); Tue, 22 Mar 2022 15:57:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57046 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232528AbiCVT5S (ORCPT ); Tue, 22 Mar 2022 15:57:18 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5DF94ECCA; Tue, 22 Mar 2022 12:55:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978949; x=1679514949; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=X7ECDYnJ4KU3fMPTtb68Clefey+0lZdfZ5b6r0T7tZY=; b=VNfXsQ0pNnqrBFVRQRZq9cYqCJCskzxoUVCAxGlwuGhhYCC0Qh8vSLVr O5QipLZKzjwmtZmm054BRtdfJcLJwGGry4CcCSKe/U12EmZp7uOZgpMal dQZ6FQsmxYQ2olj00zRfla/iU9SL0It4Ga62xXfmbFO//23hhU5d04gwf Xq0qbU9E47AoWXgVJ5+TmbXqwHfF6CEqq4QSibst9WfVkB+6HhOTcNrlO DllUq7IFHMT84k+POrBUdbhd7HcYPMKafOtD9Kpk5IBGyeG3YSkowpdKd 39/T+yUkd/FjoLTc17a4bhdFF9OWL15ThjmB/H+PpjG1f0fWf2cBtAkPI g==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="157797688" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:49 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) 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.2375.17; Tue, 22 Mar 2022 12:55:48 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:42 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 07/10] net: dsa: microchip: add support for ethtool port counters Date: Wed, 23 Mar 2022 01:24:52 +0530 Message-ID: <20220322195455.703921-8-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 get_eth_**_stats() (phy/mac/ctrl) and get_stats64() 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 Reviewed-by: Florian Fainelli --- drivers/net/dsa/microchip/lan937x_main.c | 118 +++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index c7b7b9b373d7..51640234dda6 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -45,6 +45,20 @@ static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg, return lan937x_internal_phy_write(dev, addr, reg, val); } +static void lan937x_get_strings(struct dsa_switch *ds, int port, u32 stringset, + u8 *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) { @@ -357,12 +371,116 @@ static void lan937x_phylink_get_caps(struct dsa_switch *ds, int port, } } +static void lan937x_get_eth_phy_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *cnt; + + mutex_lock(&mib->cnt_mutex); + + cnt = &mib->counters[lan937x_mib_rx_sym_err]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_rx_sym_err, NULL, cnt); + + phy_stats->SymbolErrorDuringCarrier = *cnt; + + mutex_unlock(&mib->cnt_mutex); +} + +static void lan937x_get_eth_mac_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *ctr = mib->counters; + + mutex_lock(&mib->cnt_mutex); + + while (mib->cnt_ptr < dev->mib_cnt) { + lan937x_r_mib_pkt(dev, port, mib->cnt_ptr, + NULL, &mib->counters[mib->cnt_ptr]); + ++mib->cnt_ptr; + } + + mac_stats->FramesTransmittedOK = ctr[lan937x_mib_tx_mcast] + + ctr[lan937x_mib_tx_bcast] + + ctr[lan937x_mib_tx_ucast] + + ctr[lan937x_mib_tx_pause]; + + mac_stats->SingleCollisionFrames = ctr[lan937x_mib_tx_single_col]; + mac_stats->MultipleCollisionFrames = ctr[lan937x_mib_tx_mult_col]; + + mac_stats->FramesReceivedOK = ctr[lan937x_mib_rx_mcast] + + ctr[lan937x_mib_rx_bcast] + + ctr[lan937x_mib_rx_ucast] + + ctr[lan937x_mib_rx_pause]; + + mac_stats->FrameCheckSequenceErrors = ctr[lan937x_mib_rx_crc_err]; + mac_stats->AlignmentErrors = ctr[lan937x_mib_rx_align_err]; + mac_stats->OctetsTransmittedOK = ctr[lan937x_mib_tx_total]; + mac_stats->FramesWithDeferredXmissions = ctr[lan937x_mib_tx_deferred]; + mac_stats->LateCollisions = ctr[lan937x_mib_tx_late_col]; + mac_stats->FramesAbortedDueToXSColls = ctr[lan937x_mib_tx_exc_col]; + mac_stats->FramesLostDueToIntMACXmitError = ctr[lan937x_mib_tx_discard]; + + mac_stats->OctetsReceivedOK = ctr[lan937x_mib_rx_total]; + mac_stats->FramesLostDueToIntMACRcvError = ctr[lan937x_mib_rx_discard]; + mac_stats->MulticastFramesXmittedOK = ctr[lan937x_mib_tx_mcast]; + mac_stats->BroadcastFramesXmittedOK = ctr[lan937x_mib_tx_bcast]; + + mac_stats->MulticastFramesReceivedOK = ctr[lan937x_mib_rx_mcast]; + mac_stats->BroadcastFramesReceivedOK = ctr[lan937x_mib_rx_bcast]; + mac_stats->InRangeLengthErrors = ctr[lan937x_mib_rx_fragments]; + + mib->cnt_ptr = 0; + mutex_unlock(&mib->cnt_mutex); +} + +static void lan937x_get_eth_ctrl_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_ctrl_stats *ctrl_sts) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *cnt; + + mutex_lock(&mib->cnt_mutex); + + cnt = &mib->counters[lan937x_mib_rx_pause]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_rx_pause, NULL, cnt); + ctrl_sts->MACControlFramesReceived = *cnt; + + cnt = &mib->counters[lan937x_mib_tx_pause]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_tx_pause, NULL, cnt); + ctrl_sts->MACControlFramesTransmitted = *cnt; + + mutex_unlock(&mib->cnt_mutex); +} + +static void lan937x_get_stats64(struct dsa_switch *ds, int port, + struct rtnl_link_stats64 *s) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + + spin_lock(&mib->stats64_lock); + memcpy(s, &mib->stats64, sizeof(*s)); + spin_unlock(&mib->stats64_lock); +} + 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, + .get_strings = lan937x_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, + .get_eth_ctrl_stats = lan937x_get_eth_ctrl_stats, + .get_eth_mac_stats = lan937x_get_eth_mac_stats, + .get_eth_phy_stats = lan937x_get_eth_phy_stats, + .get_stats64 = lan937x_get_stats64, .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 Tue Mar 22 19:54:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12789001 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B256CC433F5 for ; Tue, 22 Mar 2022 19:56:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232256AbiCVT5e (ORCPT ); Tue, 22 Mar 2022 15:57:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232434AbiCVT5X (ORCPT ); Tue, 22 Mar 2022 15:57:23 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B16664DF52; Tue, 22 Mar 2022 12:55:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978955; x=1679514955; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MVoKun0f6EUeOWvz5e2xJ3Ag+ZUi3FPzc4l1bOHwOSA=; b=vGmPnEhATWY6tTIN8jAhZmJQ+2Vmejbrg/rJqG7tCILgA0qXqwHJQW1j P1thzG+6w3WUTxYmseJWGblSgL/czRovbP1huw2zQx3Do4UhIuhUHud2s /0gIQ5GV1PtFqt4TgtWAVZl//7sqj02lh70KoSZEe3TQ9QWx6y5DwSgMo y8hc7qtmet4GwgJbifWicyfG7G0HeMyl14DX9I7jmqZ5kQ/622fO6hQnf 0tJQ2CTR/7dxKqgBiBaikvGf8Syp/kLeO9I4RKOthiSAYQ5y0ex+wffPf PUfFOVeWLsRKjEW3EWFqZmrkjsMv4DCoyPptX12Q11NRE9QOalPey0p39 A==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="89775148" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:55:54 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:55:54 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:49 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 08/10] net: dsa: microchip: add support for port mirror operations Date: Wed, 23 Mar 2022 01:24:53 +0530 Message-ID: <20220322195455.703921-9-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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 Sniffing is limited to one port & alert the user if any new sniffing port is selected Signed-off-by: Prasanna Vengateshan Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- drivers/net/dsa/microchip/lan937x_main.c | 83 ++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 51640234dda6..504b9a4edea2 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -98,6 +98,87 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, ksz_update_port_member(dev, port); } +static int lan937x_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress, struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + int ret, p; + u8 data; + + /* Limit to one sniffer port + * Check if any of the port is already set for sniffing + * If yes, instruct the user to remove the previous entry & exit + */ + for (p = 0; p < dev->port_cnt; p++) { + /* Skip the current sniffing port */ + if (p == mirror->to_local_port) + continue; + + ret = lan937x_pread8(dev, p, P_MIRROR_CTRL, &data); + if (ret < 0) + return ret; + + if (data & PORT_MIRROR_SNIFFER) { + NL_SET_ERR_MSG_MOD(extack, + "Sniffer port is already configured, delete existing rules & retry"); + return -EBUSY; + } + } + + /* Configure ingress/egress mirroring */ + if (ingress) + ret = lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, + true); + else + ret = lan937x_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, + true); + if (ret < 0) + return ret; + + /* Configure sniffer port as other ports do not have + * PORT_MIRROR_SNIFFER is set + */ + ret = lan937x_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, true); + if (ret < 0) + return ret; + + return lan937x_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); +} + +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; + bool in_use = false; + u8 data; + int p; + + /* clear ingress/egress mirroring port */ + 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); + + /* Check if any of the port is still referring to sniffer port */ + for (p = 0; p < dev->port_cnt; p++) { + lan937x_pread8(dev, p, P_MIRROR_CTRL, &data); + + if ((data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) { + in_use = true; + break; + } + } + + /* delete sniffing if there are no other mirroring rule exist */ + if (!in_use) + lan937x_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, false); +} + static void lan937x_config_cpu_port(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -485,6 +566,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_get_caps = lan937x_phylink_get_caps, From patchwork Tue Mar 22 19:54:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12789002 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D37D1C433FE for ; Tue, 22 Mar 2022 19:56:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232833AbiCVT5n (ORCPT ); Tue, 22 Mar 2022 15:57:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232841AbiCVT5d (ORCPT ); Tue, 22 Mar 2022 15:57:33 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 088EA4EF77; Tue, 22 Mar 2022 12:56:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978963; x=1679514963; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uPEhiiDlQYioz350ez/WeiaXyv/nNniYmUdEydRriGU=; b=B7f+hBaj0tFc3ciK+G6lwg85KtRbhkBdFOoaCysAVXU76TM/N2rug4mP 5CyshrlpNBw6zW56L5mdPnZTIGjaD3VkVBAneBVXE+Lbw4vQ63EAq52f0 f0Y1FOoIY4iid57xkbx8BvV8tQLMZIAIzZWxytj4K4t/pHzKJSKx/TMSa 93YuA+4GrSkub39y7ahUP8oRInveRlehbDKIWMOlxe/bGpU7zLP/PirTq tI9tn6PS3vweLFe5fBKiBK2q01RL5z8vQFJx/ALI4RNX2BKyr5kpyfwBM 3ywO5lFiN01Os2HT3DT/JtIE5Gd6E9SNZvCfV8osPOYX6sfXKfNBsbEZG w==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="157797701" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:56:01 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Tue, 22 Mar 2022 12:56:00 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:55:55 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 09/10] net: dsa: microchip: add support for fdb and mdb management Date: Wed, 23 Mar 2022 01:24:54 +0530 Message-ID: <20220322195455.703921-10-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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. ALU1 and ALU2 are used for fdb operations. fdb_add: find any existing entries and update the port map. if ALU1 write is failed and attempt to write ALU2. If ALU2 is also failed then exit. Clear WRITE_FAIL for both ALU1 & ALU2. fdb_del: find the matching entry and clear the respective port in the port map by writing the ALU tables fdb_dump: read and dump 2 ALUs upto last entry. ALU_START bit is used to find the last entry. If the read is timed out, then pass the error message. mdb_add: Find the empty slot in ALU and update the port map & mac address by writing the ALU mdb_del: find the matching entry and delete the respective port in port map by writing the ALU For MAC address, could not use upper_32_bits() & lower_32_bits() as per Vladimir proposal since it gets accessed in terms of 16bits. I tried to have common API to get 16bits based on index but shifting seems to be straight-forward. Signed-off-by: Prasanna Vengateshan Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- drivers/net/dsa/microchip/lan937x_main.c | 515 +++++++++++++++++++++++ 1 file changed, 515 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 504b9a4edea2..5067da9488c1 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -17,6 +17,70 @@ #include "ksz_common.h" #include "lan937x_dev.h" +static u8 lan937x_get_fid(u16 vid) +{ + if (vid > ALU_FID_SIZE) + return LAN937X_GET_FID(vid); + else + return vid; +} + +static int lan937x_read_table(struct ksz_device *dev, u32 *table) +{ + int ret; + + /* read alu table */ + ret = ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); + if (ret < 0) + return ret; + + ret = ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); + if (ret < 0) + return ret; + + ret = ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); + if (ret < 0) + return ret; + + return ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); +} + +static int lan937x_write_table(struct ksz_device *dev, u32 *table) +{ + int ret; + + /* write alu table */ + ret = ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); + if (ret < 0) + return ret; + + ret = ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); + if (ret < 0) + return ret; + + ret = ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); + if (ret < 0) + return ret; + + return 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) @@ -98,6 +162,452 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, ksz_update_port_member(dev, port); } +static int lan937x_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + 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); + + /* Accessing two ALU tables through loop */ + 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]); + + ret = ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + if (ret < 0) + break; + + data = ((addr[2] << 24) | (addr[3] << 16)); + data |= ((addr[4] << 8) | addr[5]); + + ret = ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + if (ret < 0) + break; + + /* start read operation */ + ret = ksz_write32(dev, REG_SW_ALU_CTRL(i), + ALU_READ | ALU_START); + if (ret < 0) + break; + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU\n"); + break; + } + + /* read ALU entry */ + ret = lan937x_read_table(dev, alu_table); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU\n"); + break; + } + + /* 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]); + + ret = lan937x_write_table(dev, alu_table); + if (ret < 0) + break; + + ret = ksz_write32(dev, REG_SW_ALU_CTRL(i), + (ALU_WRITE | ALU_START)); + if (ret < 0) + break; + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to write ALU\n"); + break; + } + + ret = ksz_read8(dev, REG_SW_LUE_INT_STATUS__1, &val); + if (ret < 0) + break; + + /* ALU2 write failed */ + if (val & WRITE_FAIL_INT && i == 1) + dev_err(dev->dev, "Failed to write ALU\n"); + + /* if ALU1 write is failed and attempt to write ALU2, + * otherwise exit. Clear Write fail for both ALU1 & ALU2 + */ + if (val & WRITE_FAIL_INT) { + /* Write to clear the Write Fail */ + ret = ksz_write8(dev, REG_SW_LUE_INT_STATUS__1, + WRITE_FAIL_INT); + if (ret < 0) + break; + } else { + break; + } + } + + 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 dsa_db db) +{ + 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); + + /* Accessing two ALU tables through loop */ + 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]); + ret = ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + if (ret < 0) + break; + + data = ((addr[2] << 24) | (addr[3] << 16)); + data |= ((addr[4] << 8) | addr[5]); + ret = ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + if (ret < 0) + break; + + /* start read operation */ + ret = ksz_write32(dev, REG_SW_ALU_CTRL(i), + (ALU_READ | ALU_START)); + if (ret < 0) + break; + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU\n"); + break; + } + + ret = ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); + if (ret < 0) + break; + + if (alu_table[0] & ALU_V_STATIC_VALID) { + /* read ALU entry */ + ret = lan937x_read_table(dev, alu_table); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU table\n"); + break; + } + + /* 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) + memset(&alu_table, 0, sizeof(alu_table)); + } else { + memset(&alu_table, 0, sizeof(alu_table)); + } + + ret = lan937x_write_table(dev, alu_table); + if (ret < 0) + break; + + ret = ksz_write32(dev, REG_SW_ALU_CTRL(i), + (ALU_WRITE | ALU_START)); + if (ret < 0) + break; + + /* wait to be finished */ + ret = lan937x_wait_alu_ready(i, dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to delete ALU Entries\n"); + break; + } + } + + 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 timeout; + int ret, i; + + mutex_lock(&dev->alu_mutex); + + /* Accessing two ALU tables through loop */ + for (i = 0; i < ALU_STA_DYN_CNT; i++) { + /* start ALU search */ + ret = ksz_write32(dev, REG_SW_ALU_CTRL(i), + (ALU_START | ALU_SEARCH)); + if (ret < 0) + goto exit; + + do { + timeout = 1000; + do { + ret = ksz_read32(dev, REG_SW_ALU_CTRL(i), + &lan937x_data); + if (ret < 0) + goto exit; + + 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 */ + ret = lan937x_read_table(dev, alu_table); + if (ret < 0) + goto exit; + + 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 */ + ret = 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 dsa_db db) +{ + 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); + + /* Access the entries in the table */ + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + + ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + if (ret < 0) + goto exit; + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + ret = lan937x_read_table(dev, static_table); + if (ret < 0) + goto exit; + + 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) { + ret = -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; + + ret = lan937x_write_table(dev, static_table); + if (ret < 0) + goto exit; + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + if (ret < 0) + goto exit; + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret < 0) + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + return ret; +} + +static int lan937x_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) +{ + 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); + + /* Access the entries in the table */ + for (index = 0; index < dev->num_statics; index++) { + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + if (ret < 0) + goto exit; + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + ret = lan937x_read_table(dev, static_table); + if (ret < 0) + goto exit; + + 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 */ + memset(&static_table, 0, sizeof(static_table)); + } + + ret = lan937x_write_table(dev, static_table); + if (ret < 0) + goto exit; + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + if (ret < 0) + goto exit; + + /* wait to be finished */ + ret = lan937x_wait_alu_sta_ready(dev); + if (ret < 0) + 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, struct netlink_ext_ack *extack) @@ -566,6 +1076,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 Tue Mar 22 19:54:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12789004 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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD715C433F5 for ; Tue, 22 Mar 2022 19:58:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232290AbiCVT7x (ORCPT ); Tue, 22 Mar 2022 15:59:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56984 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232259AbiCVT5m (ORCPT ); Tue, 22 Mar 2022 15:57:42 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A9B194ECE5; Tue, 22 Mar 2022 12:56:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1647978968; x=1679514968; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=alt+GVmfCQP3oT5MONyZvSlYVrF0TY9sxu2v7DZkm2Y=; b=sUXPIZM6kiOaOhGBHlmwFZwCpOWlCRgTkQ0ATjfCOZyiSDsq553Pqi3N qboOaYEX2uBjxIAar1Xc00rzHb6QRj9Yt7jVxjEZZpFDRad/Dug7N6gN8 g/4SbONfiXtCDW2w6OyLzjGh7qg6benWyGbOio30H9PqYCbZg5S2BptpA 9kTYWi4UuvDCz4dLbzrjimKMRwZTjPtXX1UcXbUHdCKumPydcBtWVRY0C QMAv60prYkzIIxwJNsrzftdlY/UgvRzvh/OmtOF8X6AHVUrAmsdkk8+WQ HsxFg6n2F2/GjOj84KwXX6FXz90Mtl3CmPlMOQLMUV3uQXgGwR0lScfMZ Q==; X-IronPort-AV: E=Sophos;i="5.90,202,1643698800"; d="scan'208";a="166737732" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Mar 2022 12:56:08 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) 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.2375.17; Tue, 22 Mar 2022 12:56:07 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2375.17 via Frontend Transport; Tue, 22 Mar 2022 12:56:01 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Subject: [PATCH v10 net-next 10/10] net: dsa: microchip: add support for vlan operations Date: Wed, 23 Mar 2022 01:24:55 +0530 Message-ID: <20220322195455.703921-11-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220322195455.703921-1-prasanna.vengateshan@microchip.com> References: <20220322195455.703921-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. The VLAN aware is a global setting. Mixed vlan filterings are not supported. vlan_filtering_is_global is made as true in lan937x_setup function. Signed-off-by: Prasanna Vengateshan Reviewed-by: Florian Fainelli --- drivers/net/dsa/microchip/lan937x_main.c | 186 +++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 5067da9488c1..f1489c5c7229 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -17,6 +17,14 @@ #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 u8 lan937x_get_fid(u16 vid) { if (vid > ALU_FID_SIZE) @@ -25,6 +33,97 @@ static u8 lan937x_get_fid(u16 vid) return vid; } +static int lan937x_get_vlan_table(struct ksz_device *dev, u16 vid, + struct lan937x_vlan *vlan_entry) +{ + u32 data; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ret = ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); + if (ret < 0) + goto exit; + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret < 0) + goto exit; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &data); + if (ret < 0) + goto exit; + + vlan_entry->valid = !!(data & VLAN_VALID); + vlan_entry->fid = data & VLAN_FID_M; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, + &vlan_entry->untag_prtmap); + if (ret < 0) + goto exit; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, + &vlan_entry->fwd_map); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + if (ret < 0) + goto exit; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static int lan937x_set_vlan_table(struct ksz_device *dev, u16 vid, + struct lan937x_vlan *vlan_entry) +{ + u32 data; + int ret; + + mutex_lock(&dev->vlan_mutex); + + data = vlan_entry->valid ? VLAN_VALID : 0; + data |= vlan_entry->fid; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY__4, data); + if (ret < 0) + goto exit; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, + vlan_entry->untag_prtmap); + if (ret < 0) + goto exit; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_entry->fwd_map); + if (ret < 0) + goto exit; + + ret = ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); + if (ret < 0) + goto exit; + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret < 0) + goto exit; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + static int lan937x_read_table(struct ksz_device *dev, u32 *table) { int ret; @@ -162,6 +261,90 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, ksz_update_port_member(dev, port); } +static int lan937x_port_vlan_filtering(struct dsa_switch *ds, int port, + bool flag, + struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + + /* enable/disable VLAN mode, once enabled, look up process starts + * and then forwarding and discarding are done based on port + * membership of the VLAN table + */ + return lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, flag); +} + +static int lan937x_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct ksz_device *dev = ds->priv; + struct lan937x_vlan vlan_entry; + int ret; + + ret = lan937x_get_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to get vlan table"); + return ret; + } + + vlan_entry.fid = lan937x_get_fid(vlan->vid); + vlan_entry.valid = true; + + /* set/clear switch port when updating vlan table registers */ + if (untagged) + vlan_entry.untag_prtmap |= BIT(port); + else + vlan_entry.untag_prtmap &= ~BIT(port); + + vlan_entry.fwd_map |= BIT(port); + + ret = lan937x_set_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set vlan table"); + return ret; + } + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { + ret = lan937x_pwrite16(dev, port, REG_PORT_DEFAULT_VID, + vlan->vid); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set pvid"); + return ret; + } + } + + return 0; +} + +static int lan937x_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + struct lan937x_vlan vlan_entry; + int ret; + + ret = lan937x_get_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + dev_err(dev->dev, "Failed to get vlan table\n"); + return ret; + } + + /* clear port fwd map & untag entries*/ + vlan_entry.fwd_map &= ~BIT(port); + vlan_entry.untag_prtmap &= ~BIT(port); + + ret = lan937x_set_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + dev_err(dev->dev, "Failed to set vlan table\n"); + return ret; + } + + return 0; +} + static int lan937x_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, struct dsa_db db) @@ -1076,6 +1259,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,