From patchwork Mon Feb 7 17:21: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: 12737743 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 066A1C47081 for ; Mon, 7 Feb 2022 17:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377266AbiBGR1W (ORCPT ); Mon, 7 Feb 2022 12:27:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45022 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346068AbiBGRXa (ORCPT ); Mon, 7 Feb 2022 12:23:30 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 63A7BC0401DC; Mon, 7 Feb 2022 09:23:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254609; x=1675790609; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eZychptXoH+ychXe9Jw+hRlk0fakUZ3gzxL+NSx7waw=; b=NcYGNdhQYUbahV+5hsmHLyfP/K9WBh4Ef3cQH79mE5YB23NpHdUfzb30 eUMePjwRVLRK3JwoeEKd/TtHIZC7lnByARmpChVxDIk+S21yogD63wTgF yKFI0qxktIK2Wx1R/TrG3pQIpToLRA6PggUh1JXDpBXNpW5Pugacxy8tS Mob53YTem6aNgyX3Yo5R+/rMG3bhxZ27Pcr3m9PpGGwVoe/0pL7mWtXiq M20RRO23aSMS7gGaIl0DPynhPZbviqyIaPJQRs+ayqMEcWulj8jb/X6Xk zrC/mnnDLd3aJy9vTwTgHeLcmQP5rG4+Xh5D680ddamPPe4QTRWUne2jg g==; IronPort-SDR: Tn8Bj053obmzmBf3EdSVeXGPPDBpRgaBVaRbWimcLTqBlmOTeNRGiokbCI3D5m5LoBVvtDvjXM 3bnoaFPsP12YM8yl9WVqIjUGyK953gqyqlNKURJkv9AeiupybgqgjtXgTzloWD5xjf5L7zd6EG nBXl+38pBofmd1ZpYqaHA3l4KZzdVc+rxRn9Y4uTD+0UPZZX9anStwvaGbSosJhMfxof/+vsko kyUt8Xe5yDUasmT87+XzpMmIGF7eP400AFKBWb5/BNkS6H8Mo5viQg/ce17MYLyTjkro8H9BzW +cqj5nL1L3ZrogAn0zNvQtyC X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="84924991" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:26 -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; Mon, 7 Feb 2022 10:22:25 -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; Mon, 7 Feb 2022 10:22:19 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , , Rob Herring Subject: [PATCH v8 net-next 01/10] dt-bindings: net: dsa: dt bindings for microchip lan937x Date: Mon, 7 Feb 2022 22:51:55 +0530 Message-ID: <20220207172204.589190-2-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 179 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 180 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..5657a0b89e4e --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml @@ -0,0 +1,179 @@ +# 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 + +patternProperties: + "^(ethernet-)?ports$": + patternProperties: + "^(ethernet-)?port@[0-7]+$": + allOf: + - if: + properties: + phy-mode: + contains: + enum: + - rgmii + - rgmii-rxid + - rgmii-txid + - rgmii-id + then: + properties: + rx-internal-delay-ps: + $ref: "#/$defs/internal-delay-ps" + tx-internal-delay-ps: + $ref: "#/$defs/internal-delay-ps" + +required: + - compatible + - reg + +$defs: + internal-delay-ps: + description: Delay is in pico seconds + enum: [0, 2000] + default: 0 + +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 = <&t1phy4>; + }; + port@7 { + reg = <7>; + label = "lan3"; + phy-mode = "internal"; + phy-handle = <&t1phy5>; + }; + }; + + 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>; + }; + t1phy4: ethernet-phy@6{ + reg = <0x6>; + }; + t1phy5: ethernet-phy@7{ + reg = <0x7>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index c7169da15ab4..4449cc2e9c69 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12630,6 +12630,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 Mon Feb 7 17:21:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737724 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 48D12C46467 for ; Mon, 7 Feb 2022 17:28:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1359540AbiBGR1P (ORCPT ); Mon, 7 Feb 2022 12:27:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346182AbiBGRXg (ORCPT ); Mon, 7 Feb 2022 12:23:36 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ACB77C0401D6 for ; Mon, 7 Feb 2022 09:23:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254616; x=1675790616; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=M5RUw9aInzvMr/cEGUCrZ6Um3TAA0XPSudFDktRPWxc=; b=t8O1J8xnCD7oP0n6KyZELv8p00Tw/bORcgV5ZiMlCta+HSwGc4g+VUkX QIh8YiolWUbg4EB+p9sCNuQSm4CoE7m6110YbnbAadk1bn+1sI0uSq27U JK6YAmHxmflRBi8uSdQjJcXyR8/hCbs4hu7g7eGHw3SaxPwJu7qGIFMPB cHbpgT9nf7iUB0wYOeaBouh2/nDaU2068hNApKklx1GxPMcwr4bSIodY4 CPb/YcU3gpl/jMNmokIoLsF64cNSskKcLkv90EHlmY3zN2Wy75CHDUIXm JMMCFqGyxTEB6TGJy/uv2rs6zCM6hL9y3JzwVjr0H9pv/lTS689mmCXRV w==; IronPort-SDR: 62TR9QcmVvCj++gip/XlOvuNjlF3kWQCUrK/cDOiCybD0eGQG4shPZnORH0nfGsci5dzuhfxDl VHgoL7HW4KybsDk2mU8OLXw6AKCn9O1ZNsXjBhtV2MdLwv1j97LIGtqEtgXnk3nVm8rZNkQlnR EBb1St6pf/LUnmdkK5WsSbt4qX2bdc6q9Tm0VGHOJd10U2AYxTc0k458iksV07tqVc3TNzsiTO i4cJ2TfV1xXWgiPpehjlppI7QfBPdMknRuH6GUR4SUBqeNFM1lEXFWGmKFSvV3Dl4Qn+fgm6hm qeoSgd5D2EOsn2nhXgwSqmB8 X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="147879263" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:32 -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; Mon, 7 Feb 2022 10:22:32 -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; Mon, 7 Feb 2022 10:22:26 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 02/10] net: dsa: move mib->cnt_ptr reset code to ksz_common.c Date: Mon, 7 Feb 2022 22:51:56 +0530 Message-ID: <20220207172204.589190-3-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 5dc9899bc0a6..2de2302b9a50 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -448,8 +448,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 a85d990896b0..21900cab96b3 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -292,9 +292,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 7e33ec73f803..196aa4fc1100 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -122,8 +122,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 Mon Feb 7 17:21:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737740 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 6690DC3527B for ; Mon, 7 Feb 2022 17:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377443AbiBGR10 (ORCPT ); Mon, 7 Feb 2022 12:27:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45166 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346218AbiBGRXn (ORCPT ); Mon, 7 Feb 2022 12:23:43 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AB08EC0401D6; Mon, 7 Feb 2022 09:23:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254623; x=1675790623; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sTcaFWkCU5SH9tJAhAVoQQ0OveeFFhJTJud5zNFjEP8=; b=dGNEOMFqQnnyauJ4DJCuDZzsulxq7wgRSBb8RW+y5ZSOmawL7GAPRZKA pxD5ggqBf41TfdqMRyevOtOvSp2luySmeS93C8uymP1Vaj1qhV4fJr6Zb Sw2/F4slYCjOGL/DEhwLBf7XnptqiN1vVgGB4ORlzFdVV/w7dkjmsIqbJ b3jQD4Ugab2wUNqWtK9UbBy+ipD10w5QPY9lPQ8hMng8gNe+EzaNIRYJa L3G/qETYhkaVBvZiJU7OlyZsoQfQcoDJKonQE0qAvQ9gUVt673CQN9le6 7smBpwb1hMhax9nlZ835tr7Nve8ZrxK+K9qtdtuTLdo+Ec+l/mkMDy5Xp Q==; IronPort-SDR: YrlYwoAf4YFm6mNkNivjIVumcVIqFV9SUdJsgUjgHOwmUhqbwmVCiameJRUywSl4DWZ6gTFWTA AK+R5yCxbhCw4OyXtp2YFaRR/+YSns2x1Sd7sP8Baj+pjnHNZ/iH/6f+mPWxTlmrz7RTHtXmpm 8FUP+/y7/R+4wuLoobzOkaOM4YVnCF1SekNc2Tw1/IFSUY7ceAgHCk7uAPWxY+pVfHP2XNL10q 4+EHQ4+ZTKTa0VOQfc1Jm/JhJ2gbvOQbr7gWcNibSAfLUqXZUxdQf5HHi68CxIFIzLA8lh+tYq zwfcDcOSrIlmv/xvsHcWi0/J X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="147879284" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:39 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:22:38 -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; Mon, 7 Feb 2022 10:22:32 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 03/10] net: phy: Add support for LAN937x T1 phy driver Date: Mon, 7 Feb 2022 22:51:57 +0530 Message-ID: <20220207172204.589190-4-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 Microchip LAN937x T1 phy driver. The sequence of initialization is used commonly for both LAN87xx and LAN937x drivers. The new initialization sequence is an improvement to existing LAN87xx and it is shared with LAN937x. Also relevant comments are added in the existing code and existing soft-reset customized code has been replaced with genphy_soft_reset(). access_ereg_clr_poll_timeout() API is introduced for polling phy bank write and this is linked with PHYACC_ATTR_MODE_POLL. Finally introduced function table for LAN937X_T1_PHY_ID along with microchip_t1_phy_driver struct. Signed-off-by: Prasanna Vengateshan --- drivers/net/phy/microchip_t1.c | 342 ++++++++++++++++++++++++++------- 1 file changed, 273 insertions(+), 69 deletions(-) diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c index bc50224d43dd..9d729b56d884 100644 --- a/drivers/net/phy/microchip_t1.c +++ b/drivers/net/phy/microchip_t1.c @@ -37,6 +37,7 @@ #define PHYACC_ATTR_MODE_READ 0 #define PHYACC_ATTR_MODE_WRITE 1 #define PHYACC_ATTR_MODE_MODIFY 2 +#define PHYACC_ATTR_MODE_POLL 3 #define PHYACC_ATTR_BANK_SMI 0 #define PHYACC_ATTR_BANK_MISC 1 @@ -50,8 +51,47 @@ #define LAN87XX_CABLE_TEST_OPEN 1 #define LAN87XX_CABLE_TEST_SAME_SHORT 2 +#define T1_MODE_STAT_REG 0x11 +#define T1_DSCR_LOCK_STATUS_MSK BIT(3) +#define T1_LINK_UP_MSK BIT(0) + +#define T1_REG_BANK_SEL_MASK 0x7 +#define T1_REG_BANK_SEL 8 +#define T1_REG_ADDR_MASK 0xFF + +#define T1_M_STATUS_REG 0x0A +#define T1_LOCAL_RX_OK BIT(13) +#define T1_REMOTE_RX_OK BIT(12) + +#define LAN87XX_PHY_ID 0x0007c150 +#define LAN937X_T1_PHY_ID 0x0007c181 +#define LAN87XX_PHY_ID_MASK 0xfffffff0 +#define LAN937X_PHY_ID_MASK 0xfffffff0 + +/* T1 Registers */ +#define T1_AFE_PORT_CFG1_REG 0x0B +#define T1_POWER_DOWN_CONTROL_REG 0x1A +#define T1_SLV_FD_MULT_CFG_REG 0x18 +#define T1_CDR_CFG_PRE_LOCK_REG 0x05 +#define T1_CDR_CFG_POST_LOCK_REG 0x06 +#define T1_LCK_STG2_MUFACT_CFG_REG 0x1A +#define T1_LCK_STG3_MUFACT_CFG_REG 0x1B +#define T1_POST_LCK_MUFACT_CFG_REG 0x1C +#define T1_TX_RX_FIFO_CFG_REG 0x02 +#define T1_TX_LPF_FIR_CFG_REG 0x55 +#define T1_SQI_CONFIG_REG 0x2E +#define T1_MDIO_CONTROL2_REG 0x10 +#define T1_INTERRUPT_SOURCE_REG 0x18 +#define T1_INTERRUPT2_SOURCE_REG 0x08 +#define T1_EQ_FD_STG1_FRZ_CFG 0x69 +#define T1_EQ_FD_STG2_FRZ_CFG 0x6A +#define T1_EQ_FD_STG3_FRZ_CFG 0x6B +#define T1_EQ_FD_STG4_FRZ_CFG 0x6C +#define T1_EQ_WT_FD_LCK_FRZ_CFG 0x6D +#define T1_PST_EQ_LCK_STG1_FRZ_CFG 0x6E + #define DRIVER_AUTHOR "Nisar Sayed " -#define DRIVER_DESC "Microchip LAN87XX T1 PHY driver" +#define DRIVER_DESC "Microchip LAN87XX/LAN937X T1 PHY driver" struct access_ereg_val { u8 mode; @@ -64,12 +104,16 @@ struct access_ereg_val { static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank, u8 offset, u16 val) { + u8 prev_bank; u16 ereg = 0; int rc = 0; + u16 t; + /* return if mode and bank are invalid */ if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX) return -EINVAL; + /* if the bank is SMI, then call phy_read() & phy_write() directly */ if (bank == PHYACC_ATTR_BANK_SMI) { if (mode == PHYACC_ATTR_MODE_WRITE) rc = phy_write(phydev, offset, val); @@ -79,16 +123,43 @@ static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank, } if (mode == PHYACC_ATTR_MODE_WRITE) { + /* Initialize to Write Mode */ ereg = LAN87XX_EXT_REG_CTL_WR_CTL; + + /* Write the data to be written in to the Bank */ rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val); if (rc < 0) return rc; } else { + /* Initialize to Read Mode */ ereg = LAN87XX_EXT_REG_CTL_RD_CTL; } ereg |= (bank << 8) | offset; + /* DSP bank access workaround for lan937x */ + if (phydev->phy_id == LAN937X_T1_PHY_ID) { + /* Read previous selected bank */ + rc = phy_read(phydev, LAN87XX_EXT_REG_CTL); + if (rc < 0) + return rc; + + /* store the prev_bank */ + prev_bank = (rc >> T1_REG_BANK_SEL) & T1_REG_BANK_SEL_MASK; + + if (bank != prev_bank && bank == PHYACC_ATTR_BANK_DSP) { + t = ereg & ~T1_REG_ADDR_MASK; + + t &= ~LAN87XX_EXT_REG_CTL_WR_CTL; + t |= LAN87XX_EXT_REG_CTL_RD_CTL; + + /* access twice for DSP bank change,dummy access */ + rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, t); + if (rc < 0) + return rc; + } + } + rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg); if (rc < 0) return rc; @@ -117,6 +188,18 @@ static int access_ereg_modify_changed(struct phy_device *phydev, return rc; } +static int access_ereg_clr_poll_timeout(struct phy_device *phydev, u8 bank, + u8 offset, u16 mask, u16 clr) +{ + int val; + + if (bank != PHYACC_ATTR_BANK_SMI) + return -EINVAL; + + return phy_read_poll_timeout(phydev, offset, val, (val & mask) == clr, + 150, 30000, true); +} + static int lan87xx_config_rgmii_delay(struct phy_device *phydev) { int rc; @@ -157,68 +240,151 @@ static int lan87xx_config_rgmii_delay(struct phy_device *phydev) static int lan87xx_phy_init(struct phy_device *phydev) { static const struct access_ereg_val init[] = { - /* TX Amplitude = 5 */ - {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_AFE, 0x0B, - 0x000A, 0x001E}, - /* Clear SMI interrupts */ - {PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 0x18, - 0, 0}, - /* Clear MISC interrupts */ - {PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 0x08, - 0, 0}, - /* Turn on TC10 Ring Oscillator (ROSC) */ - {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_MISC, 0x20, - 0x0020, 0x0020}, - /* WUR Detect Length to 1.2uS, LPC Detect Length to 1.09uS */ - {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_PCS, 0x20, - 0x283C, 0}, - /* Wake_In Debounce Length to 39uS, Wake_Out Length to 79uS */ - {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x21, - 0x274F, 0}, - /* Enable Auto Wake Forward to Wake_Out, ROSC on, Sleep, - * and Wake_In to wake PHY - */ - {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x20, - 0x80A7, 0}, - /* Enable WUP Auto Fwd, Enable Wake on MDI, Wakeup Debouncer - * to 128 uS - */ - {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x24, - 0xF110, 0}, - /* Enable HW Init */ - {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_SMI, 0x1A, - 0x0100, 0x0100}, + /* TXPD/TXAMP6 Configs */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE, + T1_AFE_PORT_CFG1_REG, 0x002D, 0 }, + /* HW_Init Hi and Force_ED */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, + T1_POWER_DOWN_CONTROL_REG, 0x0308, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_EQ_FD_STG1_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_EQ_FD_STG2_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_EQ_FD_STG3_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_EQ_FD_STG4_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_EQ_WT_FD_LCK_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_PST_EQ_LCK_STG1_FRZ_CFG, 0x0002, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_SLV_FD_MULT_CFG_REG, 0x0D53, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_CDR_CFG_PRE_LOCK_REG, 0x0AB2, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_CDR_CFG_POST_LOCK_REG, 0x0AB3, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_LCK_STG2_MUFACT_CFG_REG, 0x0AEA, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_LCK_STG3_MUFACT_CFG_REG, 0x0AEB, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_POST_LCK_MUFACT_CFG_REG, 0x0AEB, 0 }, + /* Pointer delay */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_RX_FIFO_CFG_REG, 0x1C00, 0 }, + /* Tx iir edits */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1861, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1061, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1922, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1122, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1983, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1183, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1944, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1144, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x18c5, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x10c5, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1846, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1046, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1807, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1007, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1808, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1008, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1809, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1009, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180A, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100A, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180B, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100B, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180C, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100C, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180D, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100D, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180E, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100E, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x180F, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x100F, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1810, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1010, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1811, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1011, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 }, + /* SQI enable */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, + T1_SQI_CONFIG_REG, 0x9572, 0 }, + /* Flag LPS and WUR as idle errors */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, + T1_MDIO_CONTROL2_REG, 0x0014, 0 }, + /* Restore state machines without clearing registers */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, + T1_POWER_DOWN_CONTROL_REG, 0x0200, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, + T1_MDIO_CONTROL2_REG, 0x0094, 0 }, + { PHYACC_ATTR_MODE_POLL, PHYACC_ATTR_BANK_SMI, + T1_MDIO_CONTROL2_REG, 0x0080, 0 }, + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE, + T1_AFE_PORT_CFG1_REG, 0x000C, 0 }, + /* Read INTERRUPT_SOURCE Register */ + { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, + T1_INTERRUPT_SOURCE_REG, 0, 0 }, + /* Read INTERRUPT_SOURCE Register */ + { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, + T1_INTERRUPT2_SOURCE_REG, 0, 0 }, + /* HW_Init Hi */ + { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, + T1_POWER_DOWN_CONTROL_REG, 0x0300, 0 }, }; int rc, i; - /* Start manual initialization procedures in Managed Mode */ - rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI, - 0x1a, 0x0000, 0x0100); - if (rc < 0) - return rc; - - /* Soft Reset the SMI block */ - rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI, - 0x00, 0x8000, 0x8000); + /* phy Soft reset */ + rc = genphy_soft_reset(phydev); if (rc < 0) return rc; - /* Check to see if the self-clearing bit is cleared */ - usleep_range(1000, 2000); - rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, - PHYACC_ATTR_BANK_SMI, 0x00, 0); - if (rc < 0) - return rc; - if ((rc & 0x8000) != 0) - return -ETIMEDOUT; - /* PHY Initialization */ for (i = 0; i < ARRAY_SIZE(init); i++) { - if (init[i].mode == PHYACC_ATTR_MODE_MODIFY) { - rc = access_ereg_modify_changed(phydev, init[i].bank, - init[i].offset, - init[i].val, - init[i].mask); + if (init[i].mode == PHYACC_ATTR_MODE_POLL) { + rc = access_ereg_clr_poll_timeout(phydev, init[i].bank, + init[i].offset, + init[i].val, + init[i].mask); } else { rc = access_ereg(phydev, init[i].mode, init[i].bank, init[i].offset, init[i].val); @@ -273,6 +439,9 @@ static int lan87xx_config_init(struct phy_device *phydev) { int rc = lan87xx_phy_init(phydev); + if (rc < 0) + phydev_err(phydev, "failed to initialize phy\n"); + return rc < 0 ? rc : 0; } @@ -504,32 +673,67 @@ static int lan87xx_cable_test_get_status(struct phy_device *phydev, return 0; } -static struct phy_driver microchip_t1_phy_driver[] = { - { - .phy_id = 0x0007c150, - .phy_id_mask = 0xfffffff0, - .name = "Microchip LAN87xx T1", - .flags = PHY_POLL_CABLE_TEST, +static int lan937x_read_status(struct phy_device *phydev) +{ + int val; - .features = PHY_BASIC_T1_FEATURES, + val = phy_read(phydev, T1_MODE_STAT_REG); - .config_init = lan87xx_config_init, + if (val < 0) + return val; - .config_intr = lan87xx_phy_config_intr, - .handle_interrupt = lan87xx_handle_interrupt, + if (val & T1_LINK_UP_MSK) + phydev->link = 1; + else + phydev->link = 0; + + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_100; + phydev->pause = 0; + phydev->asym_pause = 0; - .suspend = genphy_suspend, - .resume = genphy_resume, + return 0; +} + +static int lan937x_config_init(struct phy_device *phydev) +{ + /* lan87xx & lan937x follows same init sequence */ + return lan87xx_config_init(phydev); +} + +static struct phy_driver microchip_t1_phy_driver[] = { + { + .phy_id = LAN87XX_PHY_ID, + .phy_id_mask = LAN87XX_PHY_ID_MASK, + .name = "LAN87xx T1", + .flags = PHY_POLL_CABLE_TEST, + .features = PHY_BASIC_T1_FEATURES, + .config_init = lan87xx_config_init, + .config_intr = lan87xx_phy_config_intr, + .handle_interrupt = lan87xx_handle_interrupt, + .suspend = genphy_suspend, + .resume = genphy_resume, .cable_test_start = lan87xx_cable_test_start, .cable_test_get_status = lan87xx_cable_test_get_status, + }, + { + .phy_id = LAN937X_T1_PHY_ID, + .phy_id_mask = LAN937X_PHY_ID_MASK, + .name = "LAN937x T1", + .read_status = lan937x_read_status, + .features = PHY_BASIC_T1_FEATURES, + .config_init = lan937x_config_init, + .suspend = genphy_suspend, + .resume = genphy_resume, } }; module_phy_driver(microchip_t1_phy_driver); static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { - { 0x0007c150, 0xfffffff0 }, - { } + { LAN87XX_PHY_ID, LAN87XX_PHY_ID_MASK }, + { LAN937X_T1_PHY_ID, LAN937X_PHY_ID_MASK }, + {} }; MODULE_DEVICE_TABLE(mdio, microchip_t1_tbl); From patchwork Mon Feb 7 17:21:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737734 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 D5078C47080 for ; Mon, 7 Feb 2022 17:28:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377027AbiBGR1T (ORCPT ); Mon, 7 Feb 2022 12:27:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346224AbiBGRXt (ORCPT ); Mon, 7 Feb 2022 12:23:49 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3E17EC0401D5 for ; Mon, 7 Feb 2022 09:23:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254628; x=1675790628; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Dly94UPRszsxGbaHdq9AVuCztjMlsZQ9xuCw10WHMlQ=; b=nNMTWtqbVLwyMKnXvkRTIjeuM07U3Xb+0Uy15CsxmRdNV4UgQgN9wTlq goh0CiCiW2KsIjXM/rpLPIf4uQt4VKLUM1Lz4tTaaQTqXqgHTVZ77y84e OF6QamVQ+ZDs7VA7FRyNbFEg95tmXBIqv1tpMC0xuWZrBxLEgRdUG3DO7 JrDphgt54SZhhDn/wYhF/TEJlQX7+3PWhHHpaZ/w1bz4pj6SQBsWWvzYT D2LIF1KfRH91i/rc7lmXXg7xCwMMryWXGsSg6AT8Y9kH8PWaodst2rrYZ bDtP4eM/UTr/ETwXpELYHzkiG+56Zo6ZNJVgAi84Tqdd/mpPCe+tkOTCG A==; IronPort-SDR: +8Kv2uL5mN3QehMXg/zb4TM48MsiQ/RKl20tOdeqYoIkYUIwROtpO70KtsLZFm4ezg8nAZ9AMN WKMibkGgYeCk2v4iRzR1P7zO7kWEzb2DE+zYgi03rBNG6RWd8rKGrwFWAU8FoAP3WVEX2jODEX Lec//HOoJZxde85GNi99solEk4xcI/VChQUVuoRz31SKKLIlTJcRLVKZsIR2qHQ4iDxKmP13cV MZQrPImdVH/c13X6sMM31j/vAwJWMKHSASuldkit3VsbVSLJ2xlliM3yWwz5TZaHgMX5tx/yk+ JJvWJn9KDtAodGLMG+iXwCx3 X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="145147772" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:44 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:22:44 -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; Mon, 7 Feb 2022 10:22:38 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 04/10] net: dsa: tag_ksz: add tag handling for Microchip LAN937x Date: Mon, 7 Feb 2022 22:51:58 +0530 Message-ID: <20220207172204.589190-5-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 ca8c14b547b4..30b7274d8c45 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -52,6 +52,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_BRCM_LEGACY_VALUE 22 #define DSA_TAG_PROTO_SJA1110_VALUE 23 #define DSA_TAG_PROTO_RTL8_4_VALUE 24 +#define DSA_TAG_PROTO_LAN937X_VALUE 25 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -79,6 +80,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_SEVILLE = DSA_TAG_PROTO_SEVILLE_VALUE, DSA_TAG_PROTO_SJA1110 = DSA_TAG_PROTO_SJA1110_VALUE, DSA_TAG_PROTO_RTL8_4 = DSA_TAG_PROTO_RTL8_4_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 Mon Feb 7 17:21:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737710 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 0AE03C433FE for ; Mon, 7 Feb 2022 17:27:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238121AbiBGR02 (ORCPT ); Mon, 7 Feb 2022 12:26:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347271AbiBGRX5 (ORCPT ); Mon, 7 Feb 2022 12:23:57 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0C39C0401D8; Mon, 7 Feb 2022 09:23:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254634; x=1675790634; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wEQR3xNJXj1v6e0R5ednQxcFEgwIcX6csRyPpMpte3I=; b=dWOIllajfLUu1bbMjmJky9Gu0Y/+epf6S60PtvoPDqx+BRCbftyPrhYn XYne6cHUSAGtvZlaA5N6FSblam5o7RhP4zL+HsrEs4v2aAPLY+s1HpKFN VHAmOz6Vui9ICd8FaiGeSaaVPk2C3T4KpTO/xZuWR2jtf8Vbi6bNdOXYy 5/UgNaF8jYHuYMQ5qnu0efrZUrD9aRiSD1hRfBs/FDnqFOWgfR/Q9FMvA d50PnUC90699s8ooTaoRaiaCA8okvFXna0IHd2VH5+kRPjyX5F+ZO30+N ly4FhusAfqXGU41PzJBrNSbsJnOtGljolrOXNAbM0wKw6AKpWLFZ40zlg Q==; IronPort-SDR: ekI4p30Vh/Fkdzr/5qN6VTklWO0bJSIE/booftWwuhxRNq8h1NlaChXc6vCIsk0qqaL5lijV9q S92ES7w4WmK/isdBDGd2OJSS4wtI3byO6VGKBGFZk99468pCpNFGTMm/k10HplDu4ocsIq1wgK QE9MK801EaQkya5DEZAWMsJHG0SUeB74jikr2QtVamyWhgKH3bgNxQk2PiYYHFFK5CtlxGQN5r 1L/u3NVXhqYkWdo3TKu+nW1S/CpCOodAC69f1V8FDFjZciPD/TW7WnS8Om0iL1goUbfDAfWlmt 70PX72IusZzTpSOdhhg8sBT2 X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="147879324" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:51 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:22:50 -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; Mon, 7 Feb 2022 10:22:44 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 05/10] net: dsa: microchip: add DSA support for microchip lan937x Date: Mon, 7 Feb 2022 22:51:59 +0530 Message-ID: <20220207172204.589190-6-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 584 +++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 116 ++++ drivers/net/dsa/microchip/lan937x_main.c | 297 ++++++++++ drivers/net/dsa/microchip/lan937x_reg.h | 688 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_spi.c | 238 ++++++++ 8 files changed, 1945 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 3db63f62f0a1..6363d022695b 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -39,6 +39,8 @@ struct ksz_port { struct ksz_port_mib mib; phy_interface_t interface; + u32 rgmii_tx_val; + u32 rgmii_rx_val; }; struct ksz_device { @@ -143,6 +145,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..e0bd1eb3d3ab --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -0,0 +1,584 @@ +// 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_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; +} + +int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg, + u16 val) +{ + u16 temp, addr_base; + unsigned int value; + int ret; + + /* Check for internal phy port */ + if (!lan937x_is_internal_phy_port(dev, addr)) + return -EOPNOTSUPP; + + 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; + + temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2))); + + ret = ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp); + 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) +{ + u16 temp, addr_base; + 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; + + 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))); + + ret = ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp); + 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)) { + /* enable flow control */ + 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++) { + 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, + .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..4b412f79854a --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -0,0 +1,116 @@ +/* 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 */ + u8 is_static:1; + u8 is_src_filter:1; + u8 is_dst_filter:1; + u8 prio_age:3; + u32 _reserv_0_1:23; + u8 mstp:3; + /* entry 2 */ + u8 is_override:1; + u8 is_use_fid:1; + u32 _reserv_1_1:22; + u8 port_forward:8; + /* entry 3 & 4*/ + u32 _reserv_2_1:9; + u8 fid:7; + u8 mac[ETH_ALEN]; +}; + +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..1b8fabdf9b35 --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -0,0 +1,297 @@ +// 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) + return err; + + if (of_property_read_u32(port, "tx-internal-delay-ps", &val)) + val = 0; + + err = lan937x_set_rgmii_delay(dev, p, val, true); + if (err) + return err; + } + + of_node_put(ports); + return 0; +} + +static int lan937x_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int ret; + + ret = lan937x_reset_switch(dev); + if (ret < 0) { + dev_err(ds->dev, "failed to reset switch\n"); + 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..5a316977a8eb --- /dev/null +++ b/drivers/net/dsa/microchip/lan937x_spi.c @@ -0,0 +1,238 @@ +// 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 int 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); + + return 0; +} + +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 Mon Feb 7 17:22:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737727 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 67FB0C4707A for ; Mon, 7 Feb 2022 17:28:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1359776AbiBGR1P (ORCPT ); Mon, 7 Feb 2022 12:27:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45288 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347310AbiBGRYA (ORCPT ); Mon, 7 Feb 2022 12:24:00 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 707EBC0401D5 for ; Mon, 7 Feb 2022 09:23:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254639; x=1675790639; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=K/Dems9iQOEVRxrZpfPMxqsvXr1p1c3uIY28BHkL7+g=; b=0yVN8m416z9kP3cXOq2sy3LB+feDHPSYC6oWeZ5gJjwYsLeaqt/JSMmq ZVnX63YmcQCjoGnKaaYBwGRtIf7WejCsKadXxXfQNS7CPbwX1Jek8hZts MUsJxS1BV/cJniJhNyJP2yZBbTeDINhF88FTYQ96hm4k89GRF24I0Jp/U oA9RZn1s4KaiEOWQB/8K/FXE+6QeRxq8fhIM6wXdRm0jyAVKJRNutZ/5Z e1FlWDzY3EDZzALo09CTGxpqlgKcuuc2z2bAsXKAWb0Whkn11u2fumHXQ 1Rm79wHTFuaR01s0TioEex/lt4Ck2D0OXEmni8zgrVurZmKsWSvsuPbZh w==; IronPort-SDR: ZKaTNCy0WEZUfQQlU438fYfA5xR0zVW42a5zKHYJlEhDpAr8zbVq22e8gKV3g5Qi2LkROWYQAq PpPp1nUY1dR92NEuXDpc0MhUARkWwrH5gfMgAfSLr75tYmpicEFGlY/CFMo7fos+AFXVeKTWdx xNhDCWYwdLvuH76P67hmFTc4T5HH9NFO63TTUKk5Dc42NUhV4fdpmc5UBBfpy39UwBV00k63WO Fe8lwygTxWbRKYM35GlAFZ7GCkvCWC2Qiywl+ZseD1ctZTlQBzVR836Dq8IPQY27f2w7TGKovu rww3F9mQawtFz1v0edPQ2GvD X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="147879334" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:22:57 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:22:56 -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; Mon, 7 Feb 2022 10:22:50 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 06/10] net: dsa: microchip: add support for phylink management Date: Mon, 7 Feb 2022 22:52:00 +0530 Message-ID: <20220207172204.589190-7-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 167 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 6 + drivers/net/dsa/microchip/lan937x_main.c | 66 +++++++++ 3 files changed, 239 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c index e0bd1eb3d3ab..d5acfc6b14b4 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.c +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -401,6 +401,173 @@ 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 (interface == PHY_INTERFACE_MODE_RGMII_TXID || + interface == PHY_INTERFACE_MODE_RGMII_ID) { + /* if the delay is 0, let us 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 (interface == PHY_INTERFACE_MODE_RGMII_RXID || + interface == PHY_INTERFACE_MODE_RGMII_ID) { + /* if the delay is 0, let us 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: + lan937x_config_gbit(dev, true, &data8); + data8 |= PORT_RGMII_SEL; + break; + 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 4b412f79854a..32167fe6f748 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.h +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -34,8 +34,14 @@ 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); + struct mib_names { int index; char string[ETH_GSTRING_LEN]; diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 1b8fabdf9b35..bddb9ce41136 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -272,6 +272,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, @@ -284,6 +346,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 Mon Feb 7 17:22:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737733 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 B5D1DC35273 for ; Mon, 7 Feb 2022 17:28:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376858AbiBGR1S (ORCPT ); Mon, 7 Feb 2022 12:27:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347982AbiBGRYH (ORCPT ); Mon, 7 Feb 2022 12:24:07 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9644EC0401D5; Mon, 7 Feb 2022 09:24:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254646; x=1675790646; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=w/JZqlKQOTQ72ycCiJ6at2Sa6bT/5IpfMb1yuC0M5ss=; b=Y/LyJN0k3zkBIpkdsJ4MSDaB/FX0uXE36KKC1sW2I6QtoK/aOE+AMrdx 324L5jirUOMdac0ETQGYu5aZ84RdslzuGVh709vd7poiMTmAsAt2aDTej 6GNDlF5a0kQRRUzuSZVc83q/XUJEDT2bmkiNblS6po6PHzAQtypaXbrMD WspAO0h2aeXFiQs7JNvsWepQp4qOXY4LWa7V4ReiB5EimhbprFa51W4if 8GGYmXxrh+xpMb/woUYgpBRX/DoPRUU2UfZmWUSC6ui9o8KsLuuk6zZ5E vA3FXwKMfY3UA28ctQcL6w+8XFevODwhYywXXBhz4hKfRNc+hqBHKQLrz w==; IronPort-SDR: bHcIWsUX6shFj40A1Wz/NGHH438+weOmbbneYcjvS0+5AI0vTAxS3XJrUrTHfjR69yU3e7CxDh FXKWLmF1qYvlYYQ/yK7wxHGbhjOoL9dznr4bdRy3A1jjv4B4DwJfRK+bFbl0kUcO7o31l6ISSe 43Bu30Z7zcGLxh5xIBwfC7Fn5OAQ80lKZa6Ys8jucu0P5vEYzV+hbPkbvEtl2bY8DMhGvhDEN2 GlRk0zGrGKuJJ0nJOS9EJkGMp58ePU9e18AQV9zxO3Ndahk+Yo/xjzNR3xRX+XWjEu/ht1hN9u mhOvIEA6HOZXqq1K3UC5AzsL X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="145147794" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:23:02 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:23:02 -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; Mon, 7 Feb 2022 10:22:57 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 07/10] net: dsa: microchip: add support for ethtool port counters Date: Mon, 7 Feb 2022 22:52:01 +0530 Message-ID: <20220207172204.589190-8-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 164 +++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index bddb9ce41136..dfeb728bf737 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) { @@ -334,12 +348,162 @@ 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; + 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; + } + + 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]; + + mib->cnt_ptr = 0; + mutex_unlock(&mib->cnt_mutex); +} + 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 Mon Feb 7 17:22:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737739 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 8783BC3527C for ; Mon, 7 Feb 2022 17:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377455AbiBGR11 (ORCPT ); Mon, 7 Feb 2022 12:27:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45376 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231874AbiBGRYO (ORCPT ); Mon, 7 Feb 2022 12:24:14 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0765DC0401D5; Mon, 7 Feb 2022 09:24:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254651; x=1675790651; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oP8aRnbeYZ85cztbreKClDQUH5UzohGZ+W2mOCUgSDg=; b=2GZB0dmBsa79GxgEZNdPs7+OWV1t/YlJ8g1Ffu5OrGJ3KHU7UZiLmLZ5 ymr1NFbv7Vc38+LHnXZRbeEal73s01uYdnqGIuYyeYkfoc6FqznvqO3ra Pe5pog16Cw23Jqalf/jhdndSCNOYwaO1oqF0PBaqgRTgo9MnwHQmroeIk 4Ed18rF7hLyC6lUYpcQJ4QL8BmiqklTVC3U+HRvBkFXX7zmTzMnjEARwE m8q3ylhrD7E803b82gFjpHQnLuviqZ2QuK5VpQkeQEF+yxxrdOB1JUSTa jO9W5XAF5mq0Yo3Cu6GbMeVIPaJub1cYJVHjOU9U8TE19dn0ODW/wONjP w==; IronPort-SDR: dbhfEh2gEBlUPL5H0Ob8GLo9IJkkVRzU32UmCngXBoV6L5cOU5fvlDdJWEQ2ZthjuSHUsW5nzu JYZR2IE5NXmpoTzpzdQ6rUyM+RlAHckugMfOXqp0crWam4CpYG967sMyuxp/5iRDKQme7puCep DOHusI756xaMpmaaytjGXQM8J7FxnkKuj96hP3QEKNAU9+mk57ZVMPMKppPPnGJYWe6QusMMQC enHU2IyfS+P1MldnxWQdnFKtGzbe5mnXB/IDxLjXiwGVHA4VUcHsVeQu+GdZMpizw//uJm1Bo0 bnQTUdSshUgttznwdm+ov086 X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="145147822" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:23: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; Mon, 7 Feb 2022 10:23:08 -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; Mon, 7 Feb 2022 10:23:02 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 08/10] net: dsa: microchip: add support for port mirror operations Date: Mon, 7 Feb 2022 22:52:02 +0530 Message-ID: <20220207172204.589190-9-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 84 ++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index dfeb728bf737..0f550eed0ee3 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -98,6 +98,88 @@ 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 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) { + dev_err(dev->dev, + "Delete existing rules towards %s & try\n", + dsa_to_port(ds, p)->name); + 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; @@ -508,6 +590,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 Mon Feb 7 17:22:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737745 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 971CFC3527E for ; Mon, 7 Feb 2022 17:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377640AbiBGR12 (ORCPT ); Mon, 7 Feb 2022 12:27:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235952AbiBGRYT (ORCPT ); Mon, 7 Feb 2022 12:24:19 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DB82C0401D6 for ; Mon, 7 Feb 2022 09:24:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254658; x=1675790658; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=O/baY3O2NJtkO7J3JO965MgJPc2xuckoPLKHYpueZy4=; b=EmdMTVt1v1YZ1Wj9q/CdXB8uyOl2h1P7I+f5+j0G640nAgn1pUgop6a+ +kljTrdWxCKa4/iBLDq8uyWRI/YI82JLYPXS6r7ZsEtXDmjKWW3FtbUSO bgu2aYKlk1IULYlFRmC6Fi00aSAFhM16eJEhjHKKNwL1BISqcQovFGRXN lrdsJbWWkq2YMj0bCURwc+PKOpLVxIQf8tKmWFiBMkFG2BFf2BQetMcHL LyiMRuBV7BUQKBSOVgDkRnxIa/9aRigQPags7JO9u316rvrUov5Uss2dw uAmPRZfdvpu9PFNfI5vDvKBzxJ1nXU7sGecDuS4v3Nw9Rj2SDJHxs8D+F A==; IronPort-SDR: dvXbUd4k6ktRAvlgDg4LgJqTtIybRk59e/EKW7ODNVJ04qcUL8ufle59Iv4UgQXJswX+bmFbNn URaLOp63XeJCzXIUEbLZdTogy3RkOOvKUuYRnWP5wbRYvuwaafQ+JVIuR6V8LYb++zFNr9LvfG U89GXe2DGlgEcGYRbOgZ5nhuvf2XBQDekyKUYPZ884MYPGSZfl5AsQHjzLdGgSg0lnLrdI3DXq eysMb4jA38DJH9K+UZtNpBSSbPjUQVoMe2MkQce5srcV4EsuoDARKZ6odScVjq73bKwWN0QVsH NDRxmWEPcjyv9p3bjIsflOTF X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="145147866" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:23:15 -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; Mon, 7 Feb 2022 10:23:14 -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; Mon, 7 Feb 2022 10:23:09 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 09/10] net: dsa: microchip: add support for fdb and mdb management Date: Mon, 7 Feb 2022 22:52:03 +0530 Message-ID: <20220207172204.589190-10-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 | 511 +++++++++++++++++++++++ 1 file changed, 511 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 0f550eed0ee3..8849ed17ff3e 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,448 @@ 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 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 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 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 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) @@ -590,6 +1096,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 Mon Feb 7 17:22:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12737737 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 15D5FC35276 for ; Mon, 7 Feb 2022 17:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377121AbiBGR1V (ORCPT ); Mon, 7 Feb 2022 12:27:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45006 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345944AbiBGRX3 (ORCPT ); Mon, 7 Feb 2022 12:23:29 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 428F0C0401D5; Mon, 7 Feb 2022 09:23:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1644254604; x=1675790604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FalV9tCtkeYD3xhU0BpyAAbJlwHjTotLyJeXZ/vUztg=; b=bFH22E+jhVANZjYu85xDxMIMU0JG+rz/EvAylLjB1m+XJh96Fexfc/SK 7NVJPnRKSGPeTaU/J7FgySH2WiOCfBfHdoNtUMSex9VIhrhWrA29IyKOB HoLr0JSovgqK/ruz0GujFCgAA3A27lOkFFouxV8x1Ql4yPLtmNKtwfFm7 v6qPNyV3qozb0ztb1oMztRfGvRtFwHqDOugxJEaViQ61Mkk6tt/IWDyxN /HszSqDIVMCFhLelGd4Dbe6XM+99sdglVAS9wSOG5GJX0cjbarZr/I9jK cl0NrvL5huHHjKax1TMnZNzy6TKEKeasBs4+ZEGgKAnGfUcES6HXDbNm2 g==; IronPort-SDR: VkSWHyDuVvx90Tnmab3pRnTSTlg9TqG8hVK6coKIBmPmQpAfySyd+27/C5Md7/fI71GJ9zZQKh Mnw9MzBWTOCVaHgvJqjkOI5lpd/jOVrfXCjf+DnTTS41UGA6sczQ5Z5vaOPRWtm3FZB8XoZsNs p1yeYbpR8uttpZZmiS64j6Oy26hPdAo6qP6NFvdYz/BfV/Hq8GEl+oETPEOOrnWlhqn9KmaZzI jV1bI3UQFrQyuvXKK6g1SJ7GmChO/LhjRjEbFoqi6KVu0rlQrxjrNIvCVy0tTkC6gzUldMPFBo boK9I8Pdo6M/Oe0uLrTpgrx8 X-IronPort-AV: E=Sophos;i="5.88,350,1635231600"; d="scan'208";a="145147879" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Feb 2022 10:23:21 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.17; Mon, 7 Feb 2022 10:23:20 -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; Mon, 7 Feb 2022 10:23:14 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v8 net-next 10/10] net: dsa: microchip: add support for vlan operations Date: Mon, 7 Feb 2022 22:52:04 +0530 Message-ID: <20220207172204.589190-11-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220207172204.589190-1-prasanna.vengateshan@microchip.com> References: <20220207172204.589190-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 8849ed17ff3e..a58a48de9475 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) { @@ -1096,6 +1279,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,