From patchwork Fri Feb 14 05:46:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974515 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AE8E5C02198 for ; Fri, 14 Feb 2025 05:51:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=uKXVvU+SLU1gf3c8hZ0tw5H4qyBC2U+/dASmSrylnWE=; b=3ModBquAj7covT9KiFX4IJlnpZ j49s1FYNcuNQ4sLoRy1XnhUyUEFzEX1NFoVFQBNv5J9NVaqPqcnTBOrWvMQPjKl2NTj070Ovyiyv9 6b6F7HOLRnA5SWK/I0hW1OAkD2bKSLq2iXi9B2l6IrevLaV9341/nnnNDYcIBD1c72eTvhKR+oXXH btnlybLsASWOvWYPGY6KiVFFGu2CQa30NJ7XyBLMUK8c19xexFs1axbj1n42f0ofuvk7b6VW/Ohmt DiuPDM0IjHLEm9WvGiJZ+5EXO+aS7lD/+5YAo2heuQhsJzpT6TQ8XGJuqNajvPcJZ6DqcGOXaFRg+ yNPtLSBA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiobY-0000000Dk2w-1HB5; Fri, 14 Feb 2025 05:51:12 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tioYz-0000000Djah-43rl for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 05:48:35 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=uKXVvU+SLU1gf3c8hZ0tw5H4qyBC2U+/dASmSrylnWE=; b=c5eAHezRGpF9PoznWjw7ndEZ5y LG4tZ397a1GGuQn+RwBqL4z38aoykMwpkMT6HadUnKmdl941y6AYQztS6CNiee0CD4367YEkQtOkI J9k2B3huL6ae6bVwYcmgN7KbKe7W5fHzPGDR59ZOYmardTsiUd2VfUJgyaaibyX5iJI6/BrHRrt+Y HzHa6hQLkKy2W8yjk3eg3wAGo0sV4f9+XOf6tGpS8N1OVFAIjN4LZ1HdzCOljhb3ad7RSyFcfIqQg Qm+5j2o8cU82ULd2BD7NF2kBFLRCTivLBapAyh2FjMtIjh+v8OwvDCoSq0ZAmOsY7VK5IYCiKc9N1 5Tlsx9dw==; Received: from [122.175.9.182] (port=5380 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tioYH-0001hH-1Z; Fri, 14 Feb 2025 11:17:49 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 01/10] dt-bindings: net: ti: Adds DUAL-EMAC mode support on PRU-ICSS2 for AM57xx SOCs Date: Fri, 14 Feb 2025 11:16:53 +0530 Message-Id: <20250214054702.1073139-2-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_214834_026266_AD7B0806 X-CRM114-Status: GOOD ( 11.00 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Parvathi Pudi Documentation update for the newly added "pruss2_eth" device tree node and its dependencies along with compatibility for PRU-ICSS Industrial Ethernet Peripheral (IEP), PRU-ICSS Enhanced Capture (eCAP) peripheral and using YAML binding document for AM57xx SoCs. Signed-off-by: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- .../devicetree/bindings/net/ti,icss-iep.yaml | 4 +- .../bindings/net/ti,icssm-prueth.yaml | 147 ++++++++++++++++++ .../bindings/net/ti,pruss-ecap.yaml | 32 ++++ .../devicetree/bindings/soc/ti/ti,pruss.yaml | 9 ++ 4 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml create mode 100644 Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml diff --git a/Documentation/devicetree/bindings/net/ti,icss-iep.yaml b/Documentation/devicetree/bindings/net/ti,icss-iep.yaml index e36e3a622904..858d74638167 100644 --- a/Documentation/devicetree/bindings/net/ti,icss-iep.yaml +++ b/Documentation/devicetree/bindings/net/ti,icss-iep.yaml @@ -8,6 +8,8 @@ title: Texas Instruments ICSS Industrial Ethernet Peripheral (IEP) module maintainers: - Md Danish Anwar + - Parvathi Pudi + - Basharath Hussain Khaja properties: compatible: @@ -19,7 +21,7 @@ properties: - const: ti,am654-icss-iep - const: ti,am654-icss-iep - + - const: ti,am5728-icss-iep reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml new file mode 100644 index 000000000000..1dffa6bd7a88 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/ti,icssm-prueth.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments ICSSM PRUSS Ethernet + +maintainers: + - Roger Quadros + - Andrew F. Davis + - Parvathi Pudi + - Basharath Hussain Khaja + +description: + Ethernet based on the Programmable Real-Time Unit and Industrial + Communication Subsystem. + +properties: + compatible: + enum: + - ti,am57-prueth # for AM57x SoC family + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to OCMC SRAM node + + ti,mii-rt: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to MII_RT module's syscon regmap + + ti,iep: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to IEP (Industrial Ethernet Peripheral) for ICSS + + ti,ecap: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to Enhanced Capture (eCAP) event for ICSS + + interrupts: + items: + - description: High priority Rx Interrupt specifier. + - description: Low priority Rx Interrupt specifier. + + interrupt-names: + items: + - const: rx_hp + - const: rx_lp + + ethernet-ports: + type: object + additionalProperties: false + + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + + patternProperties: + ^ethernet-port@[0-1]$: + type: object + description: ICSSM PRUETH external ports + $ref: ethernet-controller.yaml# + unevaluatedProperties: false + + properties: + reg: + items: + - enum: [0, 1] + description: ICSSM PRUETH port number + + interrupts: + maxItems: 3 + + interrupt-names: + items: + - const: rx + - const: emac_ptp_tx + - const: hsr_ptp_tx + + required: + - reg + + anyOf: + - required: + - ethernet-port@0 + - required: + - ethernet-port@1 + +required: + - compatible + - sram + - ti,mii-rt + - ti,iep + - ti,ecap + - ethernet-ports + - interrupts + - interrupt-names + +allOf: + - $ref: /schemas/remoteproc/ti,pru-consumer.yaml# + +unevaluatedProperties: false + +examples: + - | + /* Dual-MAC Ethernet application node on PRU-ICSS2 */ + pruss2_eth: pruss2-eth { + compatible = "ti,am57-prueth"; + ti,prus = <&pru2_0>, <&pru2_1>; + sram = <&ocmcram1>; + ti,mii-rt = <&pruss2_mii_rt>; + ti,iep = <&pruss2_iep>; + ti,ecap = <&pruss2_ecap>; + interrupts = <20 2 2>, <21 3 3>; + interrupt-names = "rx_hp", "rx_lp"; + interrupt-parent = <&pruss2_intc>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + pruss2_emac0: ethernet-port@0 { + reg = <0>; + phy-handle = <&pruss2_eth0_phy>; + phy-mode = "mii"; + interrupts = <20 2 2>, <26 6 6>, <23 6 6>; + interrupt-names = "rx", "emac_ptp_tx", "hsr_ptp_tx"; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + pruss2_emac1: ethernet-port@1 { + reg = <1>; + phy-handle = <&pruss2_eth1_phy>; + phy-mode = "mii"; + interrupts = <21 3 3>, <27 9 7>, <24 9 7>; + interrupt-names = "rx", "emac_ptp_tx", "hsr_ptp_tx"; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml b/Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml new file mode 100644 index 000000000000..42f217099b2e --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/ti,pruss-ecap.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments PRU-ICSS Enhanced Capture (eCAP) event module + +maintainers: + - Murali Karicheri + - Parvathi Pudi + - Basharath Hussain Khaja + +properties: + compatible: + const: ti,pruss-ecap + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pruss2_ecap: ecap@30000 { + compatible = "ti,pruss-ecap"; + reg = <0x30000 0x60>; + }; diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml b/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml index 927b3200e29e..594f54264a8c 100644 --- a/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml @@ -251,6 +251,15 @@ patternProperties: type: object + ecap@[a-f0-9]+$: + description: + PRU-ICSS has a Enhanced Capture (eCAP) event module which can generate + and capture periodic timer based events which will be used for features + like RX Pacing to rise interrupt when the timer event has occurred. + Each PRU-ICSS instance has one eCAP modeule irrespective of SOCs. + + type: object + mii-rt@[a-f0-9]+$: description: | Real-Time Ethernet to support multiple industrial communication protocols. From patchwork Fri Feb 14 05:46:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974517 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E40BCC02198 for ; Fri, 14 Feb 2025 05:54:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=8GRsZCD9xf2OK4MnXp45Kwc9kF4xVdkgWV1Smal+W/M=; b=qVO3T2p0H09eKYoGd/h5EyuYIy +tR/kELcmRBjfWw4hZ3fwC9O1KfFmCs5ZBSyeYT/6H8JuH2Yi/oiKIQXnHr/aNBcZMSzqkCbjLOk/ iziq8ByskR9SGV+t49hSW8PeAH6LTISUhbDR1F2KNL9+iWmFVTMP5A/C9WmIWbLtew2nCrbg2fUzB 8+8vovUwP7cRgp2felx2oroINA3j9tC12qG5IvO2N6mm26dXhMC/LfaVg8V1EMUVVceulk2YrRzA8 85/Y51XfishaQCe2Ji+MncKfzpoZ+ptJPXC+hCyLxr3qNXtNY3jNg1l7DUhoer5szQ1i+rmFHgr4s Pjtir4qA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tioeM-0000000DkNe-3TTd; Fri, 14 Feb 2025 05:54:06 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tioZL-0000000DjdH-1E30 for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 05:48:57 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=8GRsZCD9xf2OK4MnXp45Kwc9kF4xVdkgWV1Smal+W/M=; b=dtI29qum+4wVJ4q3UNu6rtgeXH ckAvqTSO8ejCAPnGDrk6cKHEmqVA1UrtgJ6SolQKhpTZpsX5FvK3SU6syMKJ3mtaBOnszLFocPTMD 43tQtKMMBpOurFB0MkArhS3+BRLuNiMMnbiSZXXrFJeYtxFwH4qDnmtgF8RiiV4EfBBKHzVqPE1ne 9SbPwgukJa+WtCMGXpWVwDcldMAETyj1wBiicxrrQC3VoCZoFOVN7Nmx968xM+JYpCGlZpat4ey4k NLX/hnIdiuzeYW2lBbGFwqfPftKc+HR8eDbsAo2Y92rqXNwzqUvA2P/i1sfthOV8or55QLcKM8lWe ycIaK/QA==; Received: from [122.175.9.182] (port=5380 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tioYd-0001hH-05; Fri, 14 Feb 2025 11:18:11 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 02/10] net: ti: prueth: Adds ICSSM Ethernet driver Date: Fri, 14 Feb 2025 11:16:54 +0530 Message-Id: <20250214054702.1073139-3-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_214855_380281_51243A33 X-CRM114-Status: GOOD ( 24.53 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Updates Kernel configuration to enable PRUETH driver and its dependencies along with makefile changes to add the new PRUETH driver. Changes includes init and deinit of ICSSM PRU Ethernet driver including net dev registration and firmware loading for DUAL-MAC mode running on PRU-ICSS2 instance. Changes also includes link handling, PRU booting, default firmware loading and PRU stopping using existing remoteproc driver APIs. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/Kconfig | 12 + drivers/net/ethernet/ti/Makefile | 3 + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 527 +++++++++++++++++++ drivers/net/ethernet/ti/icssm/icssm_prueth.h | 100 ++++ 4 files changed, 642 insertions(+) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth.c create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth.h diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 0d5a862cd78a..96ad084f1dce 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -227,4 +227,16 @@ config TI_ICSS_IEP To compile this driver as a module, choose M here. The module will be called icss_iep. +config TI_PRUETH + tristate "TI PRU Ethernet EMAC driver" + depends on PRU_REMOTEPROC + depends on NET_SWITCHDEV + select TI_ICSS_IEP + imply PTP_1588_CLOCK + help + Some TI SoCs has Programmable Realtime Units (PRUs) cores which can + support Single or Dual Ethernet ports with help of firmware code running + on PRU cores. This driver supports remoteproc based communication to + PRU firmware to expose ethernet interface to Linux. + endif # NET_VENDOR_TI diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index cbcf44806924..93c0a4d0e33a 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -3,6 +3,9 @@ # Makefile for the TI network device drivers. # +obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o +icssm-prueth-y := icssm/icssm_prueth.o + obj-$(CONFIG_TI_CPSW) += cpsw-common.o obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c new file mode 100644 index 000000000000..3e9baa1a9412 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Texas Instruments ICSSM Ethernet Driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icssm_prueth.h" + +/* called back by PHY layer if there is change in link state of hw port*/ +static void icssm_emac_adjust_link(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct phy_device *phydev = emac->phydev; + bool new_state = false; + unsigned long flags; + + spin_lock_irqsave(&emac->lock, flags); + + if (phydev->link) { + /* check the mode of operation */ + if (phydev->duplex != emac->duplex) { + new_state = true; + emac->duplex = phydev->duplex; + } + if (phydev->speed != emac->speed) { + new_state = true; + emac->speed = phydev->speed; + } + if (!emac->link) { + new_state = true; + emac->link = 1; + } + } else if (emac->link) { + new_state = true; + emac->link = 0; + } + + if (new_state) + phy_print_status(phydev); + + if (emac->link) { + /* reactivate the transmit queue if it is stopped */ + if (netif_running(ndev) && netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } else { + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + } + + spin_unlock_irqrestore(&emac->lock, flags); +} + +static int icssm_emac_set_boot_pru(struct prueth_emac *emac, + struct net_device *ndev) +{ + const struct prueth_firmware *pru_firmwares; + struct prueth *prueth = emac->prueth; + const char *fw_name; + int ret; + + pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1]; + fw_name = pru_firmwares->fw_name[prueth->eth_type]; + if (!fw_name) { + netdev_err(ndev, "eth_type %d not supported\n", + prueth->eth_type); + return -ENODEV; + } + + ret = rproc_set_firmware(emac->pru, fw_name); + if (ret) { + netdev_err(ndev, "failed to set PRU0 firmware %s: %d\n", + fw_name, ret); + return ret; + } + + ret = rproc_boot(emac->pru); + if (ret) { + netdev_err(ndev, "failed to boot PRU0: %d\n", ret); + return ret; + } + + return ret; +} + +/** + * icssm_emac_ndo_open - EMAC device open + * @ndev: network adapter device + * + * Called when system wants to start the interface. + * + * Return: 0 for a successful open, or appropriate error code + */ +static int icssm_emac_ndo_open(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret; + + ret = icssm_emac_set_boot_pru(emac, ndev); + if (ret) + return ret; + + /* start PHY */ + phy_start(emac->phydev); + + return 0; +} + +/** + * icssm_emac_ndo_stop - EMAC device stop + * @ndev: network adapter device + * + * Called when system wants to stop or down the interface. + * + * Return: Always 0 (Success) + */ +static int icssm_emac_ndo_stop(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + /* stop PHY */ + phy_stop(emac->phydev); + + rproc_shutdown(emac->pru); + + return 0; +} + +static const struct net_device_ops emac_netdev_ops = { + .ndo_open = icssm_emac_ndo_open, + .ndo_stop = icssm_emac_ndo_stop, +}; + +/* get emac_port corresponding to eth_node name */ +static int icssm_prueth_node_port(struct device_node *eth_node) +{ + u32 port_id; + int ret; + + ret = of_property_read_u32(eth_node, "reg", &port_id); + if (ret) + return ret; + + if (port_id == 0) + return PRUETH_PORT_MII0; + else if (port_id == 1) + return PRUETH_PORT_MII1; + else + return PRUETH_PORT_INVALID; +} + +/* get MAC instance corresponding to eth_node name */ +static int icssm_prueth_node_mac(struct device_node *eth_node) +{ + u32 port_id; + int ret; + + ret = of_property_read_u32(eth_node, "reg", &port_id); + if (ret) + return ret; + + if (port_id == 0) + return PRUETH_MAC0; + else if (port_id == 1) + return PRUETH_MAC1; + else + return PRUETH_MAC_INVALID; +} + +static int icssm_prueth_netdev_init(struct prueth *prueth, + struct device_node *eth_node) +{ + struct prueth_emac *emac; + struct net_device *ndev; + enum prueth_port port; + enum prueth_mac mac; + int ret; + + port = icssm_prueth_node_port(eth_node); + if (port == PRUETH_PORT_INVALID) + return -EINVAL; + + mac = icssm_prueth_node_mac(eth_node); + if (mac == PRUETH_MAC_INVALID) + return -EINVAL; + + ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac)); + if (!ndev) + return -ENOMEM; + + SET_NETDEV_DEV(ndev, prueth->dev); + emac = netdev_priv(ndev); + prueth->emac[mac] = emac; + emac->prueth = prueth; + emac->ndev = ndev; + emac->port_id = port; + + /* by default eth_type is EMAC */ + switch (port) { + case PRUETH_PORT_MII0: + emac->pru = prueth->pru0; + break; + case PRUETH_PORT_MII1: + emac->pru = prueth->pru1; + break; + default: + return -EINVAL; + } + /* get mac address from DT and set private and netdev addr */ + ret = of_get_ethdev_address(eth_node, ndev); + if (!is_valid_ether_addr(ndev->dev_addr)) { + eth_hw_addr_random(ndev); + dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", + port, ndev->dev_addr); + } + ether_addr_copy(emac->mac_addr, ndev->dev_addr); + + /* connect PHY */ + emac->phydev = of_phy_get_and_connect(ndev, eth_node, + icssm_emac_adjust_link); + if (!emac->phydev) { + dev_dbg(prueth->dev, "PHY connection failed\n"); + ret = -EPROBE_DEFER; + goto free; + } + + /* remove unsupported modes */ + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT); + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); + + ndev->netdev_ops = &emac_netdev_ops; + + return 0; +free: + emac->ndev = NULL; + prueth->emac[mac] = NULL; + free_netdev(ndev); + + return ret; +} + +static void icssm_prueth_netdev_exit(struct prueth *prueth, + struct device_node *eth_node) +{ + struct prueth_emac *emac; + enum prueth_mac mac; + + mac = icssm_prueth_node_mac(eth_node); + if (mac == PRUETH_MAC_INVALID) + return; + + emac = prueth->emac[mac]; + if (!emac) + return; + + phy_disconnect(emac->phydev); + + free_netdev(emac->ndev); + prueth->emac[mac] = NULL; +} + +static int icssm_prueth_probe(struct platform_device *pdev) +{ + struct device_node *eth0_node = NULL, *eth1_node = NULL; + struct device_node *eth_node, *eth_ports_node; + enum pruss_pru_id pruss_id0, pruss_id1; + struct device *dev = &pdev->dev; + struct device_node *np; + struct prueth *prueth; + int i, ret; + + np = dev->of_node; + if (!np) + return -ENODEV; /* we don't support non DT */ + + prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); + if (!prueth) + return -ENOMEM; + + platform_set_drvdata(pdev, prueth); + prueth->dev = dev; + prueth->fw_data = device_get_match_data(dev); + + eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); + if (!eth_ports_node) + return -ENOENT; + + for_each_child_of_node(eth_ports_node, eth_node) { + u32 reg; + + if (strcmp(eth_node->name, "ethernet-port")) + continue; + ret = of_property_read_u32(eth_node, "reg", ®); + if (ret < 0) { + dev_err(dev, "%pOF error reading port_id %d\n", + eth_node, ret); + } + + of_node_get(eth_node); + + if (reg == 0) { + eth0_node = eth_node; + if (!of_device_is_available(eth0_node)) { + of_node_put(eth0_node); + eth0_node = NULL; + } + } else if (reg == 1) { + eth1_node = eth_node; + if (!of_device_is_available(eth1_node)) { + of_node_put(eth1_node); + eth1_node = NULL; + } + } else { + dev_err(dev, "port reg should be 0 or 1\n"); + } + } + + of_node_put(eth_ports_node); + + /* At least one node must be present and available else we fail */ + if (!eth0_node && !eth1_node) { + dev_err(dev, "neither port0 nor port1 node available\n"); + return -ENODEV; + } + + if (eth0_node == eth1_node) { + dev_err(dev, "port0 and port1 can't have same reg\n"); + of_node_put(eth0_node); + return -ENODEV; + } + + prueth->eth_node[PRUETH_MAC0] = eth0_node; + prueth->eth_node[PRUETH_MAC1] = eth1_node; + + if (eth0_node) { + prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0); + if (IS_ERR(prueth->pru0)) { + ret = PTR_ERR(prueth->pru0); + if (ret != -EPROBE_DEFER) + dev_err(dev, "unable to get PRU0: %d\n", ret); + goto put_pru; + } + } + + if (eth1_node) { + prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1); + if (IS_ERR(prueth->pru1)) { + ret = PTR_ERR(prueth->pru1); + if (ret != -EPROBE_DEFER) + dev_err(dev, "unable to get PRU1: %d\n", ret); + goto put_pru; + } + } + + /* setup netdev interfaces */ + if (eth0_node) { + ret = icssm_prueth_netdev_init(prueth, eth0_node); + if (ret) { + if (ret != -EPROBE_DEFER) { + dev_err(dev, "netdev init %s failed: %d\n", + eth0_node->name, ret); + } + goto put_pru; + } + } + + if (eth1_node) { + ret = icssm_prueth_netdev_init(prueth, eth1_node); + if (ret) { + if (ret != -EPROBE_DEFER) { + dev_err(dev, "netdev init %s failed: %d\n", + eth1_node->name, ret); + } + goto netdev_exit; + } + } + + /* register the network devices */ + if (eth0_node) { + ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); + if (ret) { + dev_err(dev, "can't register netdev for port MII0"); + goto netdev_exit; + } + + prueth->registered_netdevs[PRUETH_MAC0] = + prueth->emac[PRUETH_MAC0]->ndev; + } + + if (eth1_node) { + ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); + if (ret) { + dev_err(dev, "can't register netdev for port MII1"); + goto netdev_unregister; + } + + prueth->registered_netdevs[PRUETH_MAC1] = + prueth->emac[PRUETH_MAC1]->ndev; + } + + if (eth1_node) + of_node_put(eth1_node); + if (eth0_node) + of_node_put(eth0_node); + return 0; + +netdev_unregister: + for (i = 0; i < PRUETH_NUM_MACS; i++) { + if (!prueth->registered_netdevs[i]) + continue; + unregister_netdev(prueth->registered_netdevs[i]); + } + +netdev_exit: + for (i = 0; i < PRUETH_NUM_MACS; i++) { + eth_node = prueth->eth_node[i]; + if (!eth_node) + continue; + + icssm_prueth_netdev_exit(prueth, eth_node); + } + +put_pru: + if (eth1_node) { + if (prueth->pru1) + pru_rproc_put(prueth->pru1); + of_node_put(eth1_node); + } + + if (eth0_node) { + if (prueth->pru0) + pru_rproc_put(prueth->pru0); + of_node_put(eth0_node); + } + + return ret; +} + +static void icssm_prueth_remove(struct platform_device *pdev) +{ + struct prueth *prueth = platform_get_drvdata(pdev); + struct device_node *eth_node; + int i; + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + if (!prueth->registered_netdevs[i]) + continue; + unregister_netdev(prueth->registered_netdevs[i]); + } + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + eth_node = prueth->eth_node[i]; + if (!eth_node) + continue; + + icssm_prueth_netdev_exit(prueth, eth_node); + of_node_put(eth_node); + } + + pruss_put(prueth->pruss); + + if (prueth->eth_node[PRUETH_MAC0]) + pru_rproc_put(prueth->pru1); + if (prueth->eth_node[PRUETH_MAC1]) + pru_rproc_put(prueth->pru0); +} + +/* AM57xx SoC-specific firmware data */ +static struct prueth_private_data am57xx_prueth_pdata = { + .fw_pru[PRUSS_PRU0] = { + .fw_name[PRUSS_ETHTYPE_EMAC] = + "ti-pruss/am57xx-pru0-prueth-fw.elf", + }, + .fw_pru[PRUSS_PRU1] = { + .fw_name[PRUSS_ETHTYPE_EMAC] = + "ti-pruss/am57xx-pru1-prueth-fw.elf", + }, +}; + +static const struct of_device_id prueth_dt_match[] = { + { .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, prueth_dt_match); + +static struct platform_driver prueth_driver = { + .probe = icssm_prueth_probe, + .remove = icssm_prueth_remove, + .driver = { + .name = "prueth", + .of_match_table = prueth_dt_match, + }, +}; +module_platform_driver(prueth_driver); + +MODULE_AUTHOR("Roger Quadros "); +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h new file mode 100644 index 000000000000..7f857edc6eb2 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Texas Instruments ICSSM Ethernet driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#ifndef __NET_TI_PRUETH_H +#define __NET_TI_PRUETH_H + +#include +#include +#include +#include + +/* PRU Ethernet Type - Ethernet functionality (protocol + * implemented) provided by the PRU firmware being loaded. + */ +enum pruss_ethtype { + PRUSS_ETHTYPE_EMAC = 0, + PRUSS_ETHTYPE_HSR, + PRUSS_ETHTYPE_PRP, + PRUSS_ETHTYPE_SWITCH, + PRUSS_ETHTYPE_MAX, +}; + +/* In switch mode there are 3 real ports i.e. 3 mac addrs. + * however Linux sees only the host side port. The other 2 ports + * are the switch ports. + * In emac mode there are 2 real ports i.e. 2 mac addrs. + * Linux sees both the ports. + */ +enum prueth_port { + PRUETH_PORT_HOST = 0, /* host side port */ + PRUETH_PORT_MII0, /* physical port MII 0 */ + PRUETH_PORT_MII1, /* physical port MII 1 */ + PRUETH_PORT_INVALID, /* Invalid prueth port */ +}; + +enum prueth_mac { + PRUETH_MAC0 = 0, + PRUETH_MAC1, + PRUETH_NUM_MACS, + PRUETH_MAC_INVALID, +}; + +/** + * struct prueth_firmware - PRU Ethernet FW data + * @fw_name: firmware names of firmware to run on PRU + */ +struct prueth_firmware { + const char *fw_name[PRUSS_ETHTYPE_MAX]; +}; + +/** + * struct prueth_private_data - PRU Ethernet private data + * @fw_pru: firmware names to be used for PRUSS ethernet usecases + * @support_lre: boolean to indicate if lre is enabled + * @support_switch: boolean to indicate if switch is enabled + */ +struct prueth_private_data { + const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS]; + bool support_lre; + bool support_switch; +}; + +/* data for each emac port */ +struct prueth_emac { + struct prueth *prueth; + struct net_device *ndev; + + struct rproc *pru; + struct phy_device *phydev; + + int link; + int speed; + int duplex; + + enum prueth_port port_id; + const char *phy_id; + u8 mac_addr[6]; + phy_interface_t phy_if; + spinlock_t lock; /* serialize access */ +}; + +struct prueth { + struct device *dev; + struct pruss *pruss; + struct rproc *pru0, *pru1; + + const struct prueth_private_data *fw_data; + struct prueth_fw_offsets *fw_offsets; + + struct device_node *eth_node[PRUETH_NUM_MACS]; + struct prueth_emac *emac[PRUETH_NUM_MACS]; + struct net_device *registered_netdevs[PRUETH_NUM_MACS]; + + unsigned int eth_type; +}; +#endif /* __NET_TI_PRUETH_H */ From patchwork Fri Feb 14 05:46:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974516 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 413CDC02198 for ; Fri, 14 Feb 2025 05:52:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=1n1m1tFjvyZWrEcqitD+w80FpRSYKnoDalp1q6/Uuug=; b=S9DQfv1nivy00gWANvVUX/Nq9l SFreR0gpCdhnImjnGBMnOc7quVKpueU7ejP09rJVfZ/cDKTcKi6avjsxcTN//V6HnGFbUugwE77YP 0JxIopL7HPYQEjnoX3LlPhRiGUBP9KRz/P34XmCRgRAxuL42WCtVqRM4POGCtLSxFRB3J+z4m6fj6 5BCCEbnxmcn1vl/qZnmd65jigvHnnc6ybKEiGNw5umQ06uRJU4c4c1sC7zzHoQeegeuf7g7NO1Au3 vbuH/At9uAzC5FlX51QfnBdNPPGzA+tRFiVVWlMCKfE1JKr2nFDZ+lLfigKe1gJdnazdb1j0yyTto veAYJwkQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiocw-0000000DkBc-3rm5; Fri, 14 Feb 2025 05:52:38 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tioZ7-0000000DjjD-1Byj for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 05:48:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=1n1m1tFjvyZWrEcqitD+w80FpRSYKnoDalp1q6/Uuug=; b=QUaxhyx46UwnkWC1g1kYwtdmMn tbb2hT1Qc3Dul6qhuYN6E3FlFQQkD0G04JUJvS4eFqxh4fzjwnI6fURM4hnXHuD7sn45uTBEJVPj0 MaZjzfwz4+oez62vcAu9Dw9i4sGUcpBxJWbUCXRM91SXLmK93cN/WAaZVt9D1ZTYbo02UCY5ix/GT +JXRpnPRfY+5JoEs0FU5mGuKngJy/0jLC6nlgMWEOT6iVHmICrv7HILdOcM2xRwdk5ebJbpAXG0KJ hpARMFWoxpRGHe4Yyi0AaV3yFmAQE+Fjwc9rI6QrQeWTzBhx9x2Bk0WAVIakjVAuYkosJeeU0qKkH 19m+dVOA==; Received: from [122.175.9.182] (port=5380 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tioZ2-0001hH-2k; Fri, 14 Feb 2025 11:18:36 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 03/10] net: ti: prueth: Adds PRUETH HW and SW configuration Date: Fri, 14 Feb 2025 11:16:55 +0530 Message-Id: <20250214054702.1073139-4-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_214841_383586_3F68C576 X-CRM114-Status: GOOD ( 20.88 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Updates for MII_RT hardware peripheral configuration such as RX and TX configuration for PRU0 and PRU1, frame sizes, and MUX config. Updates for PRU-ICSS firmware register configuration and DRAM, SRAM and OCMC memory initialization, which will be used in the runtime for packet reception and transmission. DUAL-EMAC memory allocation for software queues and its supporting components such as the buffer descriptors and queue descriptors. These software queues are placed in OCMC memory and are shared with CPU by PRU-ICSS for packet receive and transmit. All declarations and macros are being used from common header file for various protocols. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/icssm/icssm_prueth.c | 427 ++++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 104 +++++ drivers/net/ethernet/ti/icssm/icssm_switch.h | 257 +++++++++++ 3 files changed, 786 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switch.h diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index 3e9baa1a9412..e2bd9e43d336 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -29,6 +29,316 @@ #include #include "icssm_prueth.h" +#include "../icssg/icssg_mii_rt.h" + +#define OCMC_RAM_SIZE (SZ_64K) + +#define TX_START_DELAY 0x40 +#define TX_CLK_DELAY_100M 0x6 + +/* Below macro is for 1528 Byte Frame support, to Allow even with + * Redundancy tag + */ +#define PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC (VLAN_ETH_FRAME_LEN + \ + ETH_FCS_LEN + \ + ICSSM_LRE_TAG_SIZE) + +/* ensure that order of PRUSS mem regions is same as enum prueth_mem */ +static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1, + PRUSS_MEM_SHRD_RAM2 }; + +static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = { + [PRUETH_PORT_QUEUE_HOST] = { + [PRUETH_QUEUE1] = { + P0_Q1_BUFFER_OFFSET, + HOST_QUEUE_DESC_OFFSET, + P0_Q1_BD_OFFSET, + P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE2] = { + P0_Q2_BUFFER_OFFSET, + HOST_QUEUE_DESC_OFFSET + 8, + P0_Q2_BD_OFFSET, + P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE3] = { + P0_Q3_BUFFER_OFFSET, + HOST_QUEUE_DESC_OFFSET + 16, + P0_Q3_BD_OFFSET, + P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE4] = { + P0_Q4_BUFFER_OFFSET, + HOST_QUEUE_DESC_OFFSET + 24, + P0_Q4_BD_OFFSET, + P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE), + }, + }, + [PRUETH_PORT_QUEUE_MII0] = { + [PRUETH_QUEUE1] = { + P1_Q1_BUFFER_OFFSET, + P1_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * + ICSS_BLOCK_SIZE), + P1_Q1_BD_OFFSET, + P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE2] = { + P1_Q2_BUFFER_OFFSET, + P1_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * + ICSS_BLOCK_SIZE), + P1_Q2_BD_OFFSET, + P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE3] = { + P1_Q3_BUFFER_OFFSET, + P1_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * + ICSS_BLOCK_SIZE), + P1_Q3_BD_OFFSET, + P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE4] = { + P1_Q4_BUFFER_OFFSET, + P1_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * + ICSS_BLOCK_SIZE), + P1_Q4_BD_OFFSET, + P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), + }, + }, + [PRUETH_PORT_QUEUE_MII1] = { + [PRUETH_QUEUE1] = { + P2_Q1_BUFFER_OFFSET, + P2_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * + ICSS_BLOCK_SIZE), + P2_Q1_BD_OFFSET, + P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE2] = { + P2_Q2_BUFFER_OFFSET, + P2_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * + ICSS_BLOCK_SIZE), + P2_Q2_BD_OFFSET, + P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE3] = { + P2_Q3_BUFFER_OFFSET, + P2_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * + ICSS_BLOCK_SIZE), + P2_Q3_BD_OFFSET, + P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), + }, + [PRUETH_QUEUE4] = { + P2_Q4_BUFFER_OFFSET, + P2_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * + ICSS_BLOCK_SIZE), + P2_Q4_BD_OFFSET, + P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), + }, + }, +}; + +static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = { + [PRUETH_PORT_QUEUE_HOST] = { + { .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, }, + { .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, }, + { .rd_ptr = P0_Q3_BD_OFFSET, .wr_ptr = P0_Q3_BD_OFFSET, }, + { .rd_ptr = P0_Q4_BD_OFFSET, .wr_ptr = P0_Q4_BD_OFFSET, }, + }, + [PRUETH_PORT_QUEUE_MII0] = { + { .rd_ptr = P1_Q1_BD_OFFSET, .wr_ptr = P1_Q1_BD_OFFSET, }, + { .rd_ptr = P1_Q2_BD_OFFSET, .wr_ptr = P1_Q2_BD_OFFSET, }, + { .rd_ptr = P1_Q3_BD_OFFSET, .wr_ptr = P1_Q3_BD_OFFSET, }, + { .rd_ptr = P1_Q4_BD_OFFSET, .wr_ptr = P1_Q4_BD_OFFSET, }, + }, + [PRUETH_PORT_QUEUE_MII1] = { + { .rd_ptr = P2_Q1_BD_OFFSET, .wr_ptr = P2_Q1_BD_OFFSET, }, + { .rd_ptr = P2_Q2_BD_OFFSET, .wr_ptr = P2_Q2_BD_OFFSET, }, + { .rd_ptr = P2_Q3_BD_OFFSET, .wr_ptr = P2_Q3_BD_OFFSET, }, + { .rd_ptr = P2_Q4_BD_OFFSET, .wr_ptr = P2_Q4_BD_OFFSET, }, + } +}; + +static void icssm_prueth_hostconfig(struct prueth *prueth) +{ + void __iomem *sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va; + void __iomem *sram; + + /* queue size lookup table */ + sram = sram_base + HOST_QUEUE_SIZE_ADDR; + writew(HOST_QUEUE_1_SIZE, sram); + writew(HOST_QUEUE_2_SIZE, sram + 2); + writew(HOST_QUEUE_3_SIZE, sram + 4); + writew(HOST_QUEUE_4_SIZE, sram + 6); + + /* queue information table */ + sram = sram_base + HOST_Q1_RX_CONTEXT_OFFSET; + memcpy_toio(sram, queue_infos[PRUETH_PORT_QUEUE_HOST], + sizeof(queue_infos[PRUETH_PORT_QUEUE_HOST])); + + /* buffer offset table */ + sram = sram_base + HOST_QUEUE_OFFSET_ADDR; + writew(P0_Q1_BUFFER_OFFSET, sram); + writew(P0_Q2_BUFFER_OFFSET, sram + 2); + writew(P0_Q3_BUFFER_OFFSET, sram + 4); + writew(P0_Q4_BUFFER_OFFSET, sram + 6); + + /* buffer descriptor offset table*/ + sram = sram_base + HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR; + writew(P0_Q1_BD_OFFSET, sram); + writew(P0_Q2_BD_OFFSET, sram + 2); + writew(P0_Q3_BD_OFFSET, sram + 4); + writew(P0_Q4_BD_OFFSET, sram + 6); + + /* queue table */ + sram = sram_base + HOST_QUEUE_DESC_OFFSET; + memcpy_toio(sram, queue_descs[PRUETH_PORT_QUEUE_HOST], + sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST])); +} + +static void icssm_prueth_mii_init(struct prueth *prueth) +{ + struct regmap *mii_rt; + u32 rxcfg_reg, rxcfg; + u32 txcfg_reg, txcfg; + + mii_rt = prueth->mii_rt; + + rxcfg = PRUSS_MII_RT_RXCFG_RX_ENABLE | + PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | + PRUSS_MII_RT_RXCFG_RX_L2_EN | + PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE | + PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS; + + /* Configuration of Port 0 Rx */ + rxcfg_reg = PRUSS_MII_RT_RXCFG0; + + regmap_write(mii_rt, rxcfg_reg, rxcfg); + + /* Configuration of Port 1 Rx */ + rxcfg_reg = PRUSS_MII_RT_RXCFG1; + + rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL; + + regmap_write(mii_rt, rxcfg_reg, rxcfg); + + txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE | + PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | + PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | + (TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) | + (TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT); + + /* Configuration of Port 0 Tx */ + txcfg_reg = PRUSS_MII_RT_TXCFG0; + + regmap_write(mii_rt, txcfg_reg, txcfg); + + txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; + + /* Configuration of Port 1 Tx */ + txcfg_reg = PRUSS_MII_RT_TXCFG1; + + regmap_write(mii_rt, txcfg_reg, txcfg); + + txcfg_reg = PRUSS_MII_RT_RX_FRMS0; + + /* Min frame length should be set to 64 to allow receive of standard + * Ethernet frames such as PTP, LLDP that will not have the tag/rct. + * Actual size written to register is size - 1 per TRM. This also + * includes CRC/FCS. + */ + txcfg = (((PRUSS_MII_RT_RX_FRMS_MIN_FRM - 1) << + PRUSS_MII_RT_RX_FRMS_MIN_FRM_SHIFT) & + PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK); + + /* For EMAC, set Max frame size to 1528 i.e size with VLAN. + * Actual size written to register is size - 1 as per TRM. + * Since driver support run time change of protocol, driver + * must overwrite the values based on Ethernet type. + */ + txcfg |= (((PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC - 1) << + PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT) & + PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK); + + regmap_write(mii_rt, txcfg_reg, txcfg); + + txcfg_reg = PRUSS_MII_RT_RX_FRMS1; + + regmap_write(mii_rt, txcfg_reg, txcfg); +} + +static void icssm_prueth_clearmem(struct prueth *prueth, enum prueth_mem region) +{ + memset_io(prueth->mem[region].va, 0, prueth->mem[region].size); +} + +static void icssm_prueth_hostinit(struct prueth *prueth) +{ + /* Clear shared RAM */ + icssm_prueth_clearmem(prueth, PRUETH_MEM_SHARED_RAM); + + /* Clear OCMC RAM */ + icssm_prueth_clearmem(prueth, PRUETH_MEM_OCMC); + + /* Clear data RAMs */ + if (prueth->eth_node[PRUETH_MAC0]) + icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM0); + if (prueth->eth_node[PRUETH_MAC1]) + icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1); + + /* Initialize host queues in shared RAM */ + icssm_prueth_hostconfig(prueth); + + /* Configure MII_RT */ + icssm_prueth_mii_init(prueth); +} + +/* This function initialize the driver in EMAC or HSR or PRP mode + * based on eth_type + */ +static void icssm_prueth_init_ethernet_mode(struct prueth *prueth) +{ + icssm_prueth_hostinit(prueth); +} + +static int icssm_prueth_emac_config(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + + /* PRU needs local shared RAM address for C28 */ + u32 sharedramaddr = ICSS_LOCAL_SHARED_RAM; + + /* PRU needs real global OCMC address for C30*/ + u32 ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa; + void __iomem *dram_base; + void __iomem *mac_addr; + void __iomem *dram; + + /* Clear data RAM */ + icssm_prueth_clearmem(prueth, emac->dram); + + dram_base = prueth->mem[emac->dram].va; + + /* setup mac address */ + mac_addr = dram_base + PORT_MAC_ADDR; + memcpy_toio(mac_addr, emac->mac_addr, 6); + + /* queue information table */ + dram = dram_base + TX_CONTEXT_Q1_OFFSET_ADDR; + memcpy_toio(dram, queue_infos[emac->port_id], + sizeof(queue_infos[emac->port_id])); + + /* queue table */ + dram = dram_base + PORT_QUEUE_DESC_OFFSET; + memcpy_toio(dram, queue_descs[emac->port_id], + sizeof(queue_descs[emac->port_id])); + + /* Set in constant table C28 of PRU0 to ICSS Shared memory */ + pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr); + + /* Set in constant table C30 of PRU0 to OCMC memory */ + pru_rproc_set_ctable(emac->pru, PRU_C30, ocmcaddr); + + return 0; +} /* called back by PHY layer if there is change in link state of hw port*/ static void icssm_emac_adjust_link(struct net_device *ndev) @@ -117,15 +427,24 @@ static int icssm_emac_set_boot_pru(struct prueth_emac *emac, static int icssm_emac_ndo_open(struct net_device *ndev) { struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; int ret; + /* set h/w MAC as user might have re-configured */ + ether_addr_copy(emac->mac_addr, ndev->dev_addr); + + if (!prueth->emac_configured) + icssm_prueth_init_ethernet_mode(prueth); + + icssm_prueth_emac_config(emac); + ret = icssm_emac_set_boot_pru(emac, ndev); if (ret) return ret; /* start PHY */ phy_start(emac->phydev); - + prueth->emac_configured |= BIT(emac->port_id); return 0; } @@ -221,9 +540,11 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, /* by default eth_type is EMAC */ switch (port) { case PRUETH_PORT_MII0: + emac->dram = PRUETH_MEM_DRAM0; emac->pru = prueth->pru0; break; case PRUETH_PORT_MII1: + emac->dram = PRUETH_MEM_DRAM1; emac->pru = prueth->pru1; break; default: @@ -295,6 +616,7 @@ static int icssm_prueth_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np; struct prueth *prueth; + struct pruss *pruss; int i, ret; np = dev->of_node; @@ -360,6 +682,12 @@ static int icssm_prueth_probe(struct platform_device *pdev) prueth->eth_node[PRUETH_MAC0] = eth0_node; prueth->eth_node[PRUETH_MAC1] = eth1_node; + prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); + if (IS_ERR(prueth->mii_rt)) { + dev_err(dev, "couldn't get mii-rt syscon regmap\n"); + return -ENODEV; + } + if (eth0_node) { prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0); if (IS_ERR(prueth->pru0)) { @@ -380,6 +708,72 @@ static int icssm_prueth_probe(struct platform_device *pdev) } } + pruss = pruss_get(prueth->pru0 ? prueth->pru0 : prueth->pru1); + if (IS_ERR(pruss)) { + ret = PTR_ERR(pruss); + dev_err(dev, "unable to get pruss handle\n"); + goto put_pru; + } + prueth->pruss = pruss; + + ret = pruss_cfg_ocp_master_ports(prueth->pruss, 1); + if (ret) { + dev_err(dev, "couldn't enabled ocp master port: %d\n", ret); + goto put_pruss; + } + + /* Configure PRUSS */ + if (eth0_node) + pruss_cfg_gpimode(pruss, pruss_id0, PRUSS_GPI_MODE_MII); + if (eth1_node) + pruss_cfg_gpimode(pruss, pruss_id1, PRUSS_GPI_MODE_MII); + pruss_cfg_miirt_enable(pruss, true); + pruss_cfg_xfr_enable(pruss, PRU_TYPE_PRU, true); + + /* Get PRUSS mem resources */ + /* OCMC is system resource which we get separately */ + for (i = 0; i < ARRAY_SIZE(pruss_mem_ids); i++) { + /* skip appropriate DRAM if not required */ + if (!eth0_node && i == PRUETH_MEM_DRAM0) + continue; + + if (!eth1_node && i == PRUETH_MEM_DRAM1) + continue; + + ret = pruss_request_mem_region(pruss, pruss_mem_ids[i], + &prueth->mem[i]); + if (ret) { + dev_err(dev, "unable to get PRUSS resource %d: %d\n", + i, ret); + goto put_mem; + } + } + + prueth->sram_pool = of_gen_pool_get(np, "sram", 0); + if (!prueth->sram_pool) { + dev_err(dev, "unable to get SRAM pool\n"); + ret = -ENODEV; + goto put_mem; + } + + prueth->ocmc_ram_size = OCMC_RAM_SIZE; + prueth->mem[PRUETH_MEM_OCMC].va = + (void __iomem *)gen_pool_alloc(prueth->sram_pool, + prueth->ocmc_ram_size); + if (!prueth->mem[PRUETH_MEM_OCMC].va) { + dev_err(dev, "unable to allocate OCMC resource\n"); + ret = -ENOMEM; + goto put_mem; + } + prueth->mem[PRUETH_MEM_OCMC].pa = gen_pool_virt_to_phys + (prueth->sram_pool, (unsigned long) + prueth->mem[PRUETH_MEM_OCMC].va); + prueth->mem[PRUETH_MEM_OCMC].size = prueth->ocmc_ram_size; + dev_dbg(dev, "ocmc: pa %pa va %p size %#zx\n", + &prueth->mem[PRUETH_MEM_OCMC].pa, + prueth->mem[PRUETH_MEM_OCMC].va, + prueth->mem[PRUETH_MEM_OCMC].size); + /* setup netdev interfaces */ if (eth0_node) { ret = icssm_prueth_netdev_init(prueth, eth0_node); @@ -388,7 +782,7 @@ static int icssm_prueth_probe(struct platform_device *pdev) dev_err(dev, "netdev init %s failed: %d\n", eth0_node->name, ret); } - goto put_pru; + goto free_pool; } } @@ -426,6 +820,9 @@ static int icssm_prueth_probe(struct platform_device *pdev) prueth->emac[PRUETH_MAC1]->ndev; } + dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", + (!eth0_node || !eth1_node) ? "single" : "dual"); + if (eth1_node) of_node_put(eth1_node); if (eth0_node) @@ -448,6 +845,21 @@ static int icssm_prueth_probe(struct platform_device *pdev) icssm_prueth_netdev_exit(prueth, eth_node); } +free_pool: + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, + prueth->ocmc_ram_size); + +put_mem: + pruss_cfg_ocp_master_ports(prueth->pruss, 0); + for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { + if (prueth->mem[i].va) + pruss_release_mem_region(pruss, &prueth->mem[i]); + } + +put_pruss: + pruss_put(prueth->pruss); + put_pru: if (eth1_node) { if (prueth->pru1) @@ -485,6 +897,16 @@ static void icssm_prueth_remove(struct platform_device *pdev) of_node_put(eth_node); } + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, + prueth->ocmc_ram_size); + + for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { + if (prueth->mem[i].va) + pruss_release_mem_region(prueth->pruss, + &prueth->mem[i]); + } + pruss_put(prueth->pruss); if (prueth->eth_node[PRUETH_MAC0]) @@ -495,6 +917,7 @@ static void icssm_prueth_remove(struct platform_device *pdev) /* AM57xx SoC-specific firmware data */ static struct prueth_private_data am57xx_prueth_pdata = { + .driver_data = PRUSS_AM57XX, .fw_pru[PRUSS_PRU0] = { .fw_name[PRUSS_ETHTYPE_EMAC] = "ti-pruss/am57xx-pru0-prueth-fw.elf", diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 7f857edc6eb2..fc59087c214d 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -13,6 +13,14 @@ #include #include +#include "icssm_switch.h" + +/* ICSSM size of redundancy tag */ +#define ICSSM_LRE_TAG_SIZE 6 + +/* PRUSS local memory map */ +#define ICSS_LOCAL_SHARED_RAM 0x00010000 + /* PRU Ethernet Type - Ethernet functionality (protocol * implemented) provided by the PRU firmware being loaded. */ @@ -24,6 +32,50 @@ enum pruss_ethtype { PRUSS_ETHTYPE_MAX, }; +#define PRUETH_IS_EMAC(p) ((p)->eth_type == PRUSS_ETHTYPE_EMAC) +#define PRUETH_IS_SWITCH(p) ((p)->eth_type == PRUSS_ETHTYPE_SWITCH) + +/** + * struct prueth_queue_desc - Queue descriptor + * @rd_ptr: Read pointer, points to a buffer descriptor in Shared PRU RAM. + * @wr_ptr: Write pointer, points to a buffer descriptor in Shared PRU RAM. + * @busy_s: Slave queue busy flag, set by slave(us) to request access from + * master(PRU). + * @status: Bit field status register, Bits: + * 0: Master queue busy flag. + * 1: Packet has been placed in collision queue. + * 2: Packet has been discarded due to overflow. + * @max_fill_level: Maximum queue usage seen. + * @overflow_cnt: Count of queue overflows. + * + * Each port has up to 4 queues with variable length. The queue is processed + * as ring buffer with read and write pointers. Both pointers are address + * pointers and increment by 4 for each buffer descriptor position. Queue has + * a length defined in constants and a status. + */ +struct prueth_queue_desc { + u16 rd_ptr; + u16 wr_ptr; + u8 busy_s; + u8 status; + u8 max_fill_level; + u8 overflow_cnt; +} __packed; + +/** + * struct prueth_queue_info - Information about a queue in memory + * @buffer_offset: buffer offset in OCMC RAM + * @queue_desc_offset: queue descriptor offset in Shared RAM + * @buffer_desc_offset: buffer descriptors offset in Shared RAM + * @buffer_desc_end: end address of buffer descriptors in Shared RAM + */ +struct prueth_queue_info { + u16 buffer_offset; + u16 queue_desc_offset; + u16 buffer_desc_offset; + u16 buffer_desc_end; +} __packed; + /* In switch mode there are 3 real ports i.e. 3 mac addrs. * however Linux sees only the host side port. The other 2 ports * are the switch ports. @@ -44,6 +96,34 @@ enum prueth_mac { PRUETH_MAC_INVALID, }; +/* In both switch & emac modes there are 3 port queues + * EMAC mode: + * RX packets for both MII0 & MII1 ports come on + * QUEUE_HOST. + * TX packets for MII0 go on QUEUE_MII0, TX packets + * for MII1 go on QUEUE_MII1. + * Switch mode: + * Host port RX packets come on QUEUE_HOST + * TX packets might have to go on MII0 or MII1 or both. + * MII0 TX queue is QUEUE_MII0 and MII1 TX queue is + * QUEUE_MII1. + */ +enum prueth_port_queue_id { + PRUETH_PORT_QUEUE_HOST = 0, + PRUETH_PORT_QUEUE_MII0, + PRUETH_PORT_QUEUE_MII1, + PRUETH_PORT_QUEUE_MAX, +}; + +/* Each port queue has 4 queues and 1 collision queue */ +enum prueth_queue_id { + PRUETH_QUEUE1 = 0, + PRUETH_QUEUE2, + PRUETH_QUEUE3, + PRUETH_QUEUE4, + PRUETH_COLQUEUE, /* collision queue */ +}; + /** * struct prueth_firmware - PRU Ethernet FW data * @fw_name: firmware names of firmware to run on PRU @@ -52,13 +132,31 @@ struct prueth_firmware { const char *fw_name[PRUSS_ETHTYPE_MAX]; }; +/* PRUeth memory range identifiers */ +enum prueth_mem { + PRUETH_MEM_DRAM0 = 0, + PRUETH_MEM_DRAM1, + PRUETH_MEM_SHARED_RAM, + PRUETH_MEM_OCMC, + PRUETH_MEM_MAX, +}; + +enum pruss_device { + PRUSS_AM57XX = 0, + PRUSS_AM43XX, + PRUSS_AM33XX, + PRUSS_K2G +}; + /** * struct prueth_private_data - PRU Ethernet private data + * @driver_data: PRU Ethernet device name * @fw_pru: firmware names to be used for PRUSS ethernet usecases * @support_lre: boolean to indicate if lre is enabled * @support_switch: boolean to indicate if switch is enabled */ struct prueth_private_data { + enum pruss_device driver_data; const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS]; bool support_lre; bool support_switch; @@ -77,6 +175,7 @@ struct prueth_emac { int duplex; enum prueth_port port_id; + enum prueth_mem dram; const char *phy_id; u8 mac_addr[6]; phy_interface_t phy_if; @@ -87,6 +186,9 @@ struct prueth { struct device *dev; struct pruss *pruss; struct rproc *pru0, *pru1; + struct pruss_mem_region mem[PRUETH_MEM_MAX]; + struct gen_pool *sram_pool; + struct regmap *mii_rt; const struct prueth_private_data *fw_data; struct prueth_fw_offsets *fw_offsets; @@ -96,5 +198,7 @@ struct prueth { struct net_device *registered_netdevs[PRUETH_NUM_MACS]; unsigned int eth_type; + size_t ocmc_ram_size; + u8 emac_configured; }; #endif /* __NET_TI_PRUETH_H */ diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h new file mode 100644 index 000000000000..b13e0706ccec --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com + */ + +#ifndef __ICSS_SWITCH_H +#define __ICSS_SWITCH_H + +/* Basic Switch Parameters + * Used to auto compute offset addresses on L3 OCMC RAM. Do not modify these + * without changing firmware accordingly + */ +#define SWITCH_BUFFER_SIZE (64 * 1024) /* L3 buffer */ +#define ICSS_BLOCK_SIZE 32 /* data bytes per BD */ +#define BD_SIZE 4 /* byte buffer descriptor */ +#define NUM_QUEUES 4 /* Queues on Port 0/1/2 */ + +#define PORT_LINK_MASK 0x1 +#define PORT_IS_HD_MASK 0x2 + +/* Physical Port queue size (number of BDs). Same for both ports */ +#define QUEUE_1_SIZE 97 /* Network Management high */ +#define QUEUE_2_SIZE 97 /* Network Management low */ +#define QUEUE_3_SIZE 97 /* Protocol specific */ +#define QUEUE_4_SIZE 97 /* NRT (IP,ARP, ICMP) */ + +/* Host queue size (number of BDs). Each BD points to data buffer of 32 bytes. + * HOST PORT QUEUES can buffer up to 4 full sized frames per queue + */ +#define HOST_QUEUE_1_SIZE 194 /* Protocol and VLAN priority 7 & 6 */ +#define HOST_QUEUE_2_SIZE 194 /* Protocol mid */ +#define HOST_QUEUE_3_SIZE 194 /* Protocol low */ +#define HOST_QUEUE_4_SIZE 194 /* NRT (IP, ARP, ICMP) */ + +#define COL_QUEUE_SIZE 0 + +/* NRT Buffer descriptor definition + * Each buffer descriptor points to a max 32 byte block and has 32 bit in size + * to have atomic operation. + * PRU can address bytewise into memory. + * Definition of 32 bit descriptor is as follows + * + * Bits Name Meaning + * ============================================================================= + * 0..7 Index points to index in buffer queue, max 256 x 32 + * byte blocks can be addressed + * 6 LookupSuccess For switch, FDB lookup was successful (source + * MAC address found in FDB). + * For RED, NodeTable lookup was successful. + * 7 Flood Packet should be flooded (destination MAC + * address found in FDB). For switch only. + * 8..12 Block_length number of valid bytes in this specific block. + * Will be <=32 bytes on last block of packet + * 13 More "More" bit indicating that there are more blocks + * 14 Shadow indicates that "index" is pointing into shadow + * buffer + * 15 TimeStamp indicates that this packet has time stamp in + * separate buffer - only needed of PTCP runs on + * host + * 16..17 Port different meaning for ingress and egress, + * Ingress: Port = 0 indicates phy port 1 and + * Port = 1 indicates phy port 2. + * Egress: 0 sends on phy port 1 and 1 sends on + * phy port 2. Port = 2 goes over MAC table + * look-up + * 18..28 Length 11 bit of total packet length which is put into + * first BD only so that host access only one BD + * 29 VlanTag indicates that packet has Length/Type field of + * 0x08100 with VLAN tag in following byte + * 30 Broadcast indicates that packet goes out on both physical + * ports, there will be two bd but only one buffer + * 31 Error indicates there was an error in the packet + */ +#define PRUETH_BD_START_FLAG_MASK BIT(0) +#define PRUETH_BD_START_FLAG_SHIFT 0 + +#define PRUETH_BD_HSR_FRAME_MASK BIT(4) +#define PRUETH_BD_HSR_FRAME_SHIFT 4 + +#define PRUETH_BD_SUP_HSR_FRAME_MASK BIT(5) +#define PRUETH_BD_SUP_HSR_FRAME_SHIFT 5 + +#define PRUETH_BD_LOOKUP_SUCCESS_MASK BIT(6) +#define PRUETH_BD_LOOKUP_SUCCESS_SHIFT 6 + +#define PRUETH_BD_SW_FLOOD_MASK BIT(7) +#define PRUETH_BD_SW_FLOOD_SHIFT 7 + +#define PRUETH_BD_SHADOW_MASK BIT(14) +#define PRUETH_BD_SHADOW_SHIFT 14 + +#define PRUETH_BD_TIMESTAMP_MASK BIT(15) +#define PRUETH_BD_TIMESTAMP_SHIT 15 + +#define PRUETH_BD_PORT_MASK GENMASK(17, 16) +#define PRUETH_BD_PORT_SHIFT 16 + +#define PRUETH_BD_LENGTH_MASK GENMASK(28, 18) +#define PRUETH_BD_LENGTH_SHIFT 18 + +#define PRUETH_BD_BROADCAST_MASK BIT(30) +#define PRUETH_BD_BROADCAST_SHIFT 30 + +#define PRUETH_BD_ERROR_MASK BIT(31) +#define PRUETH_BD_ERROR_SHIFT 31 + +/* The following offsets indicate which sections of the memory are used + * for EMAC internal tasks + */ +#define DRAM_START_OFFSET 0x1E98 +#define SRAM_START_OFFSET 0x400 + +/* General Purpose Statistics + * These are present on both PRU0 and PRU1 DRAM + */ +/* base statistics offset */ +#define STATISTICS_OFFSET 0x1F00 +#define STAT_SIZE 0x98 + +/* Offset for storing + * 1. Storm Prevention Params + * 2. PHY Speed Offset + * 3. Port Status Offset + * These are present on both PRU0 and PRU1 + */ +/* 4 bytes */ +#define STORM_PREVENTION_OFFSET_BC (STATISTICS_OFFSET + STAT_SIZE) +/* 4 bytes */ +#define PHY_SPEED_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 4) +/* 1 byte */ +#define PORT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 8) +/* 1 byte */ +#define COLLISION_COUNTER (STATISTICS_OFFSET + STAT_SIZE + 9) +/* 4 bytes */ +#define RX_PKT_SIZE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 10) +/* 4 bytes */ +#define PORT_CONTROL_ADDR (STATISTICS_OFFSET + STAT_SIZE + 14) +/* 6 bytes */ +#define PORT_MAC_ADDR (STATISTICS_OFFSET + STAT_SIZE + 18) +/* 1 byte */ +#define RX_INT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 24) +/* 4 bytes */ +#define STORM_PREVENTION_OFFSET_MC (STATISTICS_OFFSET + STAT_SIZE + 25) +/* 4 bytes */ +#define STORM_PREVENTION_OFFSET_UC (STATISTICS_OFFSET + STAT_SIZE + 29) +/* 4 bytes ? */ +#define STP_INVALID_STATE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 33) + +/* DRAM Offsets for EMAC + * Present on Both DRAM0 and DRAM1 + */ + +/* 4 queue descriptors for port tx = 32 bytes */ +#define TX_CONTEXT_Q1_OFFSET_ADDR (PORT_QUEUE_DESC_OFFSET + 32) +#define PORT_QUEUE_DESC_OFFSET (ICSS_EMAC_TTS_CYC_TX_SOF + 8) + +/* EMAC Time Triggered Send Offsets */ +#define ICSS_EMAC_TTS_CYC_TX_SOF (ICSS_EMAC_TTS_PREV_TX_SOF + 8) +#define ICSS_EMAC_TTS_PREV_TX_SOF \ + (ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET + 4) +#define ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET (ICSS_EMAC_TTS_STATUS_OFFSET \ + + 4) +#define ICSS_EMAC_TTS_STATUS_OFFSET (ICSS_EMAC_TTS_CFG_TIME_OFFSET + 4) +#define ICSS_EMAC_TTS_CFG_TIME_OFFSET (ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET + 4) +#define ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET \ + (ICSS_EMAC_TTS_CYCLE_START_OFFSET + 8) +#define ICSS_EMAC_TTS_CYCLE_START_OFFSET ICSS_EMAC_TTS_BASE_OFFSET +#define ICSS_EMAC_TTS_BASE_OFFSET DRAM_START_OFFSET + +/* Shared RAM offsets for EMAC */ + +/* Queue Descriptors */ + +/* 4 queue descriptors for port 0 (host receive). 32 bytes */ +#define HOST_QUEUE_DESC_OFFSET (HOST_QUEUE_SIZE_ADDR + 16) + +/* table offset for queue size: + * 3 ports * 4 Queues * 1 byte offset = 12 bytes + */ +#define HOST_QUEUE_SIZE_ADDR (HOST_QUEUE_OFFSET_ADDR + 8) +/* table offset for queue: + * 4 Queues * 2 byte offset = 8 bytes + */ +#define HOST_QUEUE_OFFSET_ADDR (HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR + 8) +/* table offset for Host queue descriptors: + * 1 ports * 4 Queues * 2 byte offset = 8 bytes + */ +#define HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR (HOST_Q4_RX_CONTEXT_OFFSET + 8) + +/* Host Port Rx Context */ +#define HOST_Q4_RX_CONTEXT_OFFSET (HOST_Q3_RX_CONTEXT_OFFSET + 8) +#define HOST_Q3_RX_CONTEXT_OFFSET (HOST_Q2_RX_CONTEXT_OFFSET + 8) +#define HOST_Q2_RX_CONTEXT_OFFSET (HOST_Q1_RX_CONTEXT_OFFSET + 8) +#define HOST_Q1_RX_CONTEXT_OFFSET (EMAC_PROMISCUOUS_MODE_OFFSET + 4) + +/* Promiscuous mode control */ +#define EMAC_P1_PROMISCUOUS_BIT BIT(0) +#define EMAC_P2_PROMISCUOUS_BIT BIT(1) +#define EMAC_PROMISCUOUS_MODE_OFFSET (EMAC_RESERVED + 4) +#define EMAC_RESERVED EOF_48K_BUFFER_BD + +/* allow for max 48k buffer which spans the descriptors up to 0x1800 6kB */ +#define EOF_48K_BUFFER_BD (P0_BUFFER_DESC_OFFSET + HOST_BD_SIZE + \ + PORT_BD_SIZE) + +#define HOST_BD_SIZE ((HOST_QUEUE_1_SIZE + \ + HOST_QUEUE_2_SIZE + HOST_QUEUE_3_SIZE + \ + HOST_QUEUE_4_SIZE) * BD_SIZE) +#define PORT_BD_SIZE ((QUEUE_1_SIZE + QUEUE_2_SIZE + \ + QUEUE_3_SIZE + QUEUE_4_SIZE) * 2 * BD_SIZE) + +#define END_OF_BD_POOL (P2_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE) +#define P2_Q4_BD_OFFSET (P2_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE) +#define P2_Q3_BD_OFFSET (P2_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE) +#define P2_Q2_BD_OFFSET (P2_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE) +#define P2_Q1_BD_OFFSET (P1_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE) +#define P1_Q4_BD_OFFSET (P1_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE) +#define P1_Q3_BD_OFFSET (P1_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE) +#define P1_Q2_BD_OFFSET (P1_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE) +#define P1_Q1_BD_OFFSET (P0_Q4_BD_OFFSET + HOST_QUEUE_4_SIZE * BD_SIZE) +#define P0_Q4_BD_OFFSET (P0_Q3_BD_OFFSET + HOST_QUEUE_3_SIZE * BD_SIZE) +#define P0_Q3_BD_OFFSET (P0_Q2_BD_OFFSET + HOST_QUEUE_2_SIZE * BD_SIZE) +#define P0_Q2_BD_OFFSET (P0_Q1_BD_OFFSET + HOST_QUEUE_1_SIZE * BD_SIZE) +#define P0_Q1_BD_OFFSET P0_BUFFER_DESC_OFFSET +#define P0_BUFFER_DESC_OFFSET SRAM_START_OFFSET + +/* Memory Usage of L3 OCMC RAM */ + +/* L3 64KB Memory - mainly buffer Pool */ +#define END_OF_BUFFER_POOL (P2_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \ + ICSS_BLOCK_SIZE) +#define P2_Q4_BUFFER_OFFSET (P2_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \ + ICSS_BLOCK_SIZE) +#define P2_Q3_BUFFER_OFFSET (P2_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \ + ICSS_BLOCK_SIZE) +#define P2_Q2_BUFFER_OFFSET (P2_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \ + ICSS_BLOCK_SIZE) +#define P2_Q1_BUFFER_OFFSET (P1_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \ + ICSS_BLOCK_SIZE) +#define P1_Q4_BUFFER_OFFSET (P1_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \ + ICSS_BLOCK_SIZE) +#define P1_Q3_BUFFER_OFFSET (P1_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \ + ICSS_BLOCK_SIZE) +#define P1_Q2_BUFFER_OFFSET (P1_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \ + ICSS_BLOCK_SIZE) +#define P1_Q1_BUFFER_OFFSET (P0_Q4_BUFFER_OFFSET + HOST_QUEUE_4_SIZE * \ + ICSS_BLOCK_SIZE) +#define P0_Q4_BUFFER_OFFSET (P0_Q3_BUFFER_OFFSET + HOST_QUEUE_3_SIZE * \ + ICSS_BLOCK_SIZE) +#define P0_Q3_BUFFER_OFFSET (P0_Q2_BUFFER_OFFSET + HOST_QUEUE_2_SIZE * \ + ICSS_BLOCK_SIZE) +#define P0_Q2_BUFFER_OFFSET (P0_Q1_BUFFER_OFFSET + HOST_QUEUE_1_SIZE * \ + ICSS_BLOCK_SIZE) +#define P0_COL_BUFFER_OFFSET 0xEE00 +#define P0_Q1_BUFFER_OFFSET 0x0000 + +#endif /* __ICSS_SWITCH_H */ From patchwork Fri Feb 14 07:37:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974569 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F03A2C02198 for ; Fri, 14 Feb 2025 07:40:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=KXMGgV8bs9yh7yeZaHYRVcY8hhdjnGEP2nj/eZInWGc=; b=mmHUuGE01u0SUc5kwm6ythGxuj mZe9B1pDn68Ln0ZTptw6zvY4mt8iXpoc8ObgGu/45oDuA9z4eTadq0SJN/TgpWrY2KVzmSzFy2w/c OdeTIPTkNwfLM7moAqiuYCXtaz1C/IFHlQQhzhVBPdbLNF2D1Rj8pK1kkcExag6B4qt4KI8Mg/Saf YM+hVhhxvvhFi1yUuxhW6HcEaqyUzdY4eih8Eayqyrv4Zg8nYY95GzjOkQfZ21Lp/VbjNYwLAxd7w hqdomATJqxOV4GJjkSwGNiWd57yqbOK1H704xfUFYgJOI6CZiB9HVB0EouK26tvtTAHWoTCwZeNTE rnXPBr5Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiqJ6-0000000Dz3C-0ZJC; Fri, 14 Feb 2025 07:40:16 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tiqHe-0000000DymH-1K4P for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 07:38:47 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=KXMGgV8bs9yh7yeZaHYRVcY8hhdjnGEP2nj/eZInWGc=; b=Yrf7+4zywqAw9cNN0EUP57p/Bu HuhjM4sRZlEii/rB3aEIi3ElVxwfH0St6ioHAtM5kyak9Vrlxv2MVU2oDBOlTThHVvTeagMYzrxS+ SX18X+y2z6uFXnuz0cCTkqsNh9hucn3FxYz+9FhjmeoFIzZSGZOZvxxL3u14fqo0VQ3egBNP3et7t Avn02GnJRQJJ3CUFQWZ9/0FvWwrxKy4XnxTlOrwk0HVC5JG8kMaqdyieqoOCB4vibLnFivhNNcSTc 5IqEeIZBe1dZKKSkaFxbI7JsaBhtFJcftQZ56ss6Ti8HgSKkPgpbscK3o7BkwTaFNUjZQqynL8SJ4 FF18Ul/Q==; Received: from [122.175.9.182] (port=52498 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tiqHZ-0003eJ-1v; Fri, 14 Feb 2025 13:08:41 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 04/10] net: ti: prueth: Adds link detection, RX and TX support. Date: Fri, 14 Feb 2025 13:07:51 +0530 Message-Id: <20250214073757.1076778-5-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_233846_422493_BB153C9B X-CRM114-Status: GOOD ( 22.13 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Changes corresponding to link configuration such as speed and duplexity. IRQ and handler initializations are performed for packet reception.Firmware receives the packet from the wire and stores it into OCMC queue. Next, it notifies the CPU via interrupt. Upon receiving the interrupt CPU will service the IRQ and packet will be processed by pushing the newly allocated SKB to upper layers. When the user application want to transmit a packet, it will invoke sys_send() which will inturn invoke the PRUETH driver, then it will write the packet into OCMC queues. PRU firmware will pick up the packet and transmit it on to the wire. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/icssm/icssm_prueth.c | 611 ++++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 45 ++ 2 files changed, 651 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index e2bd9e43d336..782c0650ac57 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -36,6 +36,13 @@ #define TX_START_DELAY 0x40 #define TX_CLK_DELAY_100M 0x6 +static inline void icssm_prueth_write_reg(struct prueth *prueth, + enum prueth_mem region, + unsigned int reg, u32 val) +{ + writel_relaxed(val, prueth->mem[region].va + reg); +} + /* Below macro is for 1528 Byte Frame support, to Allow even with * Redundancy tag */ @@ -299,18 +306,31 @@ static void icssm_prueth_init_ethernet_mode(struct prueth *prueth) icssm_prueth_hostinit(prueth); } -static int icssm_prueth_emac_config(struct prueth_emac *emac) +static void icssm_prueth_port_enable(struct prueth_emac *emac, bool enable) { struct prueth *prueth = emac->prueth; + void __iomem *port_ctrl; + void __iomem *ram; - /* PRU needs local shared RAM address for C28 */ - u32 sharedramaddr = ICSS_LOCAL_SHARED_RAM; + ram = prueth->mem[emac->dram].va; + port_ctrl = ram + PORT_CONTROL_ADDR; + writeb(!!enable, port_ctrl); +} - /* PRU needs real global OCMC address for C30*/ - u32 ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa; +static int icssm_prueth_emac_config(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + u32 sharedramaddr, ocmcaddr; void __iomem *dram_base; void __iomem *mac_addr; void __iomem *dram; + void __iomem *sram; + + /* PRU needs local shared RAM address for C28 */ + sharedramaddr = ICSS_LOCAL_SHARED_RAM; + /* PRU needs real global OCMC address for C30*/ + ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa; + sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va; /* Clear data RAM */ icssm_prueth_clearmem(prueth, emac->dram); @@ -331,6 +351,9 @@ static int icssm_prueth_emac_config(struct prueth_emac *emac) memcpy_toio(dram, queue_descs[emac->port_id], sizeof(queue_descs[emac->port_id])); + emac->rx_queue_descs = sram + HOST_QUEUE_DESC_OFFSET; + emac->tx_queue_descs = dram; + /* Set in constant table C28 of PRU0 to ICSS Shared memory */ pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr); @@ -340,6 +363,40 @@ static int icssm_prueth_emac_config(struct prueth_emac *emac) return 0; } +/* update phy/port status information for firmware */ +static void icssm_emac_update_phystatus(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + u32 phy_speed, port_status = 0; + enum prueth_mem region; + u32 delay; + + region = emac->dram; + phy_speed = emac->speed; + icssm_prueth_write_reg(prueth, region, PHY_SPEED_OFFSET, phy_speed); + + delay = TX_CLK_DELAY_100M; + + delay = delay << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT; + + if (emac->port_id) { + regmap_update_bits(prueth->mii_rt, + PRUSS_MII_RT_TXCFG1, + PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK, + delay); + } else { + regmap_update_bits(prueth->mii_rt, + PRUSS_MII_RT_TXCFG0, + PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK, + delay); + } + + if (emac->link) + port_status |= PORT_LINK_MASK; + + writeb(port_status, prueth->mem[region].va + PORT_STATUS_OFFSET); +} + /* called back by PHY layer if there is change in link state of hw port*/ static void icssm_emac_adjust_link(struct net_device *ndev) { @@ -369,6 +426,8 @@ static void icssm_emac_adjust_link(struct net_device *ndev) emac->link = 0; } + icssm_emac_update_phystatus(emac); + if (new_state) phy_print_status(phydev); @@ -384,6 +443,397 @@ static void icssm_emac_adjust_link(struct net_device *ndev) spin_unlock_irqrestore(&emac->lock, flags); } +static unsigned int +icssm_get_buff_desc_count(const struct prueth_queue_info *queue) +{ + unsigned int buffer_desc_count; + + buffer_desc_count = queue->buffer_desc_end - + queue->buffer_desc_offset; + buffer_desc_count /= BD_SIZE; + buffer_desc_count++; + + return buffer_desc_count; +} + +static void icssm_get_block(struct prueth_queue_desc __iomem *queue_desc, + const struct prueth_queue_info *queue, + int *write_block, int *read_block) +{ + *write_block = (readw(&queue_desc->wr_ptr) - + queue->buffer_desc_offset) / BD_SIZE; + *read_block = (readw(&queue_desc->rd_ptr) - + queue->buffer_desc_offset) / BD_SIZE; +} + +/** + * icssm_prueth_tx_enqueue - queue a packet to firmware for transmission + * + * @emac: EMAC data structure + * @skb: packet data buffer + * @queue_id: priority queue id + * + * Return: 0 (Success) + */ +static int icssm_prueth_tx_enqueue(struct prueth_emac *emac, + struct sk_buff *skb, + enum prueth_queue_id queue_id) +{ + struct prueth_queue_desc __iomem *queue_desc; + const struct prueth_queue_info *txqueue; + struct net_device *ndev = emac->ndev; + unsigned int buffer_desc_count; + int free_blocks, update_block; + bool buffer_wrapped = false; + int write_block, read_block; + void *src_addr, *dst_addr; + int pkt_block_size; + void __iomem *dram; + int txport, pktlen; + u16 update_wr_ptr; + u32 wr_buf_desc; + void *ocmc_ram; + + dram = emac->prueth->mem[emac->dram].va; + if (eth_skb_pad(skb)) { + if (netif_msg_tx_err(emac) && net_ratelimit()) + netdev_err(ndev, "packet pad failed\n"); + return -ENOMEM; + } + + /* which port to tx: MII0 or MII1 */ + txport = emac->tx_port_queue; + src_addr = skb->data; + pktlen = skb->len; + /* Get the tx queue */ + queue_desc = emac->tx_queue_descs + queue_id; + txqueue = &queue_infos[txport][queue_id]; + + buffer_desc_count = icssm_get_buff_desc_count(txqueue); + + /* the PRU firmware deals mostly in pointers already + * offset into ram, we would like to deal in indexes + * within the queue we are working with for code + * simplicity, calculate this here + */ + icssm_get_block(queue_desc, txqueue, &write_block, &read_block); + + if (write_block > read_block) { + free_blocks = buffer_desc_count - write_block; + free_blocks += read_block; + } else if (write_block < read_block) { + free_blocks = read_block - write_block; + } else { /* they are all free */ + free_blocks = buffer_desc_count; + } + + pkt_block_size = DIV_ROUND_UP(pktlen, ICSS_BLOCK_SIZE); + if (pkt_block_size > free_blocks) /* out of queue space */ + return -ENOBUFS; + + /* calculate end BD address post write */ + update_block = write_block + pkt_block_size; + + /* Check for wrap around */ + if (update_block >= buffer_desc_count) { + update_block %= buffer_desc_count; + buffer_wrapped = true; + } + + /* OCMC RAM is not cached and write order is not important */ + ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va; + dst_addr = ocmc_ram + txqueue->buffer_offset + + (write_block * ICSS_BLOCK_SIZE); + + /* Copy the data from socket buffer(DRAM) to PRU buffers(OCMC) */ + if (buffer_wrapped) { /* wrapped around buffer */ + int bytes = (buffer_desc_count - write_block) * ICSS_BLOCK_SIZE; + int remaining; + + /* bytes is integral multiple of ICSS_BLOCK_SIZE but + * entire packet may have fit within the last BD + * if pkt_info.length is not integral multiple of + * ICSS_BLOCK_SIZE + */ + if (pktlen < bytes) + bytes = pktlen; + + /* copy non-wrapped part */ + memcpy(dst_addr, src_addr, bytes); + + /* copy wrapped part */ + src_addr += bytes; + remaining = pktlen - bytes; + dst_addr = ocmc_ram + txqueue->buffer_offset; + memcpy(dst_addr, src_addr, remaining); + } else { + memcpy(dst_addr, src_addr, pktlen); + } + + /* update first buffer descriptor */ + wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) & + PRUETH_BD_LENGTH_MASK; + writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr)); + + /* update the write pointer in this queue descriptor, the firmware + * polls for this change so this will signal the start of transmission + */ + update_wr_ptr = txqueue->buffer_desc_offset + (update_block * BD_SIZE); + writew(update_wr_ptr, &queue_desc->wr_ptr); + + return 0; +} + +void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, + struct prueth_packet_info *pkt_info) +{ + pkt_info->start_offset = false; + + pkt_info->shadow = !!(buffer_descriptor & PRUETH_BD_SHADOW_MASK); + pkt_info->port = (buffer_descriptor & PRUETH_BD_PORT_MASK) >> + PRUETH_BD_PORT_SHIFT; + pkt_info->length = (buffer_descriptor & PRUETH_BD_LENGTH_MASK) >> + PRUETH_BD_LENGTH_SHIFT; + pkt_info->broadcast = !!(buffer_descriptor & PRUETH_BD_BROADCAST_MASK); + pkt_info->error = !!(buffer_descriptor & PRUETH_BD_ERROR_MASK); + pkt_info->sv_frame = false; + pkt_info->lookup_success = !!(buffer_descriptor & + PRUETH_BD_LOOKUP_SUCCESS_MASK); + pkt_info->flood = !!(buffer_descriptor & PRUETH_BD_SW_FLOOD_MASK); + pkt_info->timestamp = !!(buffer_descriptor & PRUETH_BD_TIMESTAMP_MASK); +} + +/** + * icssm_emac_rx_packet - EMAC Receive function + * + * @emac: EMAC data structure + * @bd_rd_ptr: Buffer descriptor read pointer + * @pkt_info: packet information structure + * @rxqueue: Receive queue information structure + * + * Get a packet from receive queue + * + * Return: 0 (Success) + */ +int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, + struct prueth_packet_info *pkt_info, + const struct prueth_queue_info *rxqueue) +{ + struct net_device *ndev = emac->ndev; + unsigned int buffer_desc_count; + int read_block, update_block; + unsigned int actual_pkt_len; + bool buffer_wrapped = false; + void *src_addr, *dst_addr; + u16 start_offset = 0; + struct sk_buff *skb; + int pkt_block_size; + void *ocmc_ram; + + /* the PRU firmware deals mostly in pointers already + * offset into ram, we would like to deal in indexes + * within the queue we are working with for code + * simplicity, calculate this here + */ + buffer_desc_count = icssm_get_buff_desc_count(rxqueue); + read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE; + pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE); + + /* calculate end BD address post read */ + update_block = read_block + pkt_block_size; + + /* Check for wrap around */ + if (update_block >= buffer_desc_count) { + update_block %= buffer_desc_count; + if (update_block) + buffer_wrapped = true; + } + + /* calculate new pointer in ram */ + *bd_rd_ptr = rxqueue->buffer_desc_offset + (update_block * BD_SIZE); + + /* Pkt len w/ HSR tag removed, If applicable */ + actual_pkt_len = pkt_info->length - start_offset; + + /* Allocate a socket buffer for this packet */ + skb = netdev_alloc_skb_ip_align(ndev, actual_pkt_len); + if (!skb) { + if (netif_msg_rx_err(emac) && net_ratelimit()) + netdev_err(ndev, "failed rx buffer alloc\n"); + return -ENOMEM; + } + + dst_addr = skb->data; + + /* OCMC RAM is not cached and read order is not important */ + ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va; + + /* Get the start address of the first buffer from + * the read buffer description + */ + src_addr = ocmc_ram + rxqueue->buffer_offset + + (read_block * ICSS_BLOCK_SIZE); + src_addr += start_offset; + + /* Copy the data from PRU buffers(OCMC) to socket buffer(DRAM) */ + if (buffer_wrapped) { /* wrapped around buffer */ + int bytes = (buffer_desc_count - read_block) * ICSS_BLOCK_SIZE; + int remaining; + /* bytes is integral multiple of ICSS_BLOCK_SIZE but + * entire packet may have fit within the last BD + * if pkt_info.length is not integral multiple of + * ICSS_BLOCK_SIZE + */ + if (pkt_info->length < bytes) + bytes = pkt_info->length; + + /* If applicable, account for the HSR tag removed */ + bytes -= start_offset; + + /* copy non-wrapped part */ + memcpy(dst_addr, src_addr, bytes); + + /* copy wrapped part */ + dst_addr += bytes; + remaining = actual_pkt_len - bytes; + + src_addr = ocmc_ram + rxqueue->buffer_offset; + memcpy(dst_addr, src_addr, remaining); + src_addr += remaining; + } else { + memcpy(dst_addr, src_addr, actual_pkt_len); + src_addr += actual_pkt_len; + } + + if (!pkt_info->sv_frame) { + skb_put(skb, actual_pkt_len); + + /* send packet up the stack */ + skb->protocol = eth_type_trans(skb, ndev); + local_bh_disable(); + netif_receive_skb(skb); + local_bh_enable(); + } else { + dev_kfree_skb_any(skb); + } + + /* update stats */ + ndev->stats.rx_bytes += actual_pkt_len; + ndev->stats.rx_packets++; + + return 0; +} + +/** + * icssm_emac_rx_thread - EMAC Rx interrupt thread handler + * @irq: interrupt number + * @dev_id: pointer to net_device + * + * EMAC Rx Interrupt thread handler - function to process the rx frames in a + * irq thread function. There is only limited buffer at the ingress to + * queue the frames. As the frames are to be emptied as quickly as + * possible to avoid overflow, irq thread is necessary. Current implementation + * based on NAPI poll results in packet loss due to overflow at + * the ingress queues. Industrial use case requires loss free packet + * processing. Tests shows that with threaded irq based processing, + * no overflow happens when receiving at ~92Mbps for MTU sized frames and thus + * meet the requirement for industrial use case. + * + * Return: interrupt handled condition + */ +static irqreturn_t icssm_emac_rx_thread(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_queue_desc __iomem *queue_desc; + const struct prueth_queue_info *rxqueue; + struct prueth *prueth = emac->prueth; + struct net_device_stats *ndevstats; + struct prueth_packet_info pkt_info; + int start_queue, end_queue; + void __iomem *shared_ram; + u16 bd_rd_ptr, bd_wr_ptr; + u16 update_rd_ptr; + u8 overflow_cnt; + u32 rd_buf_desc; + int used = 0; + int i, ret; + + ndevstats = &emac->ndev->stats; + shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + + start_queue = emac->rx_queue_start; + end_queue = emac->rx_queue_end; +retry: + /* search host queues for packets */ + for (i = start_queue; i <= end_queue; i++) { + queue_desc = emac->rx_queue_descs + i; + rxqueue = &queue_infos[PRUETH_PORT_HOST][i]; + + overflow_cnt = readb(&queue_desc->overflow_cnt); + if (overflow_cnt > 0) { + emac->ndev->stats.rx_over_errors += overflow_cnt; + /* reset to zero */ + writeb(0, &queue_desc->overflow_cnt); + } + + bd_rd_ptr = readw(&queue_desc->rd_ptr); + bd_wr_ptr = readw(&queue_desc->wr_ptr); + + /* while packets are available in this queue */ + while (bd_rd_ptr != bd_wr_ptr) { + /* get packet info from the read buffer descriptor */ + rd_buf_desc = readl(shared_ram + bd_rd_ptr); + icssm_parse_packet_info(prueth, rd_buf_desc, &pkt_info); + + if (pkt_info.length <= 0) { + /* a packet length of zero will cause us to + * never move the read pointer ahead, locking + * the driver, so we manually have to move it + * to the write pointer, discarding all + * remaining packets in this queue. This should + * never happen. + */ + update_rd_ptr = bd_wr_ptr; + ndevstats->rx_length_errors++; + } else if (pkt_info.length > EMAC_MAX_FRM_SUPPORT) { + /* if the packet is too large we skip it but we + * still need to move the read pointer ahead + * and assume something is wrong with the read + * pointer as the firmware should be filtering + * these packets + */ + update_rd_ptr = bd_wr_ptr; + ndevstats->rx_length_errors++; + } else { + update_rd_ptr = bd_rd_ptr; + ret = icssm_emac_rx_packet(emac, &update_rd_ptr, + &pkt_info, rxqueue); + if (ret) + return IRQ_HANDLED; + used++; + } + + /* after reading the buffer descriptor we clear it + * to prevent improperly moved read pointer errors + * from simply looking like old packets. + */ + writel(0, shared_ram + bd_rd_ptr); + + /* update read pointer in queue descriptor */ + writew(update_rd_ptr, &queue_desc->rd_ptr); + bd_rd_ptr = update_rd_ptr; + } + } + + if (used) { + used = 0; + goto retry; + } + + return IRQ_HANDLED; +} + static int icssm_emac_set_boot_pru(struct prueth_emac *emac, struct net_device *ndev) { @@ -412,6 +862,21 @@ static int icssm_emac_set_boot_pru(struct prueth_emac *emac, netdev_err(ndev, "failed to boot PRU0: %d\n", ret); return ret; } + return ret; +} + +static int icssm_emac_request_irqs(struct prueth_emac *emac) +{ + struct net_device *ndev = emac->ndev; + int ret; + + ret = request_threaded_irq(emac->rx_irq, NULL, icssm_emac_rx_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + ndev->name, ndev); + if (ret) { + netdev_err(ndev, "unable to request RX IRQ\n"); + return ret; + } return ret; } @@ -442,10 +907,27 @@ static int icssm_emac_ndo_open(struct net_device *ndev) if (ret) return ret; + ret = icssm_emac_request_irqs(emac); + if (ret) + goto rproc_shutdown; + /* start PHY */ phy_start(emac->phydev); + + /* enable the port and vlan */ + icssm_prueth_port_enable(emac, true); + prueth->emac_configured |= BIT(emac->port_id); + + if (netif_msg_drv(emac)) + dev_notice(&ndev->dev, "started\n"); + return 0; + +rproc_shutdown: + rproc_shutdown(emac->pru); + + return ret; } /** @@ -459,18 +941,116 @@ static int icssm_emac_ndo_open(struct net_device *ndev) static int icssm_emac_ndo_stop(struct net_device *ndev) { struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + + prueth->emac_configured &= ~BIT(emac->port_id); + + /* disable the mac port */ + icssm_prueth_port_enable(emac, false); /* stop PHY */ phy_stop(emac->phydev); + /* stop the PRU */ rproc_shutdown(emac->pru); + /* free rx interrupts */ + free_irq(emac->rx_irq, ndev); + + if (netif_msg_drv(emac)) + dev_notice(&ndev->dev, "stopped\n"); + return 0; } +/* VLAN-tag PCP to priority queue map for EMAC/Switch/HSR/PRP used by driver + * Index is PCP val / 2. + * low - pcp 0..3 maps to Q4 for Host + * high - pcp 4..7 maps to Q3 for Host + * low - pcp 0..3 maps to Q2 (FWD Queue) for PRU-x + * where x = 1 for PRUETH_PORT_MII0 + * 0 for PRUETH_PORT_MII1 + * high - pcp 4..7 maps to Q1 (FWD Queue) for PRU-x + */ +static const unsigned short emac_pcp_tx_priority_queue_map[] = { + PRUETH_QUEUE4, PRUETH_QUEUE4, + PRUETH_QUEUE3, PRUETH_QUEUE3, + PRUETH_QUEUE2, PRUETH_QUEUE2, + PRUETH_QUEUE1, PRUETH_QUEUE1, +}; + +static u16 icssm_prueth_get_tx_queue_id(struct prueth *prueth, + struct sk_buff *skb) +{ + u16 vlan_tci, pcp; + int err; + + err = vlan_get_tag(skb, &vlan_tci); + if (likely(err)) + pcp = 0; + else + pcp = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + + /* Below code (pcp >>= 1) is made common for all + * protocols (i.e., EMAC, RSTP, HSR and PRP)* + * pcp value 0,1 will be updated to 0 mapped to QUEUE4 + * pcp value 2,3 will be updated to 1 mapped to QUEUE4 + * pcp value 4,5 will be updated to 2 mapped to QUEUE3 + * pcp value 6,7 will be updated to 3 mapped to QUEUE3 + */ + pcp >>= 1; + + return emac_pcp_tx_priority_queue_map[pcp]; +} + +/** + * icssm_emac_ndo_start_xmit - EMAC Transmit function + * @skb: SKB pointer + * @ndev: EMAC network adapter + * + * Called by the system to transmit a packet - we queue the packet in + * EMAC hardware transmit queue + * + * Return: enum netdev_tx + */ +static enum netdev_tx icssm_emac_ndo_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret; + u16 qid; + + qid = icssm_prueth_get_tx_queue_id(emac->prueth, skb); + ret = icssm_prueth_tx_enqueue(emac, skb, qid); + if (ret) { + if (ret != -ENOBUFS && netif_msg_tx_err(emac) && + net_ratelimit()) + netdev_err(ndev, "packet queue failed: %d\n", ret); + goto fail_tx; + } + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + dev_kfree_skb_any(skb); + + return NETDEV_TX_OK; + +fail_tx: + if (ret == -ENOBUFS) { + ret = NETDEV_TX_BUSY; + } else { + /* error */ + ndev->stats.tx_dropped++; + ret = NET_XMIT_DROP; + } + + return ret; +} + static const struct net_device_ops emac_netdev_ops = { .ndo_open = icssm_emac_ndo_open, .ndo_stop = icssm_emac_ndo_stop, + .ndo_start_xmit = icssm_emac_ndo_start_xmit, }; /* get emac_port corresponding to eth_node name */ @@ -540,16 +1120,37 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, /* by default eth_type is EMAC */ switch (port) { case PRUETH_PORT_MII0: + emac->tx_port_queue = PRUETH_PORT_QUEUE_MII0; + + /* packets from MII0 are on queues 1 through 2 */ + emac->rx_queue_start = PRUETH_QUEUE1; + emac->rx_queue_end = PRUETH_QUEUE2; + emac->dram = PRUETH_MEM_DRAM0; emac->pru = prueth->pru0; break; case PRUETH_PORT_MII1: + emac->tx_port_queue = PRUETH_PORT_QUEUE_MII1; + + /* packets from MII1 are on queues 3 through 4 */ + emac->rx_queue_start = PRUETH_QUEUE3; + emac->rx_queue_end = PRUETH_QUEUE4; + emac->dram = PRUETH_MEM_DRAM1; emac->pru = prueth->pru1; break; default: return -EINVAL; } + + emac->rx_irq = of_irq_get_byname(eth_node, "rx"); + if (emac->rx_irq < 0) { + ret = emac->rx_irq; + if (ret != -EPROBE_DEFER) + dev_err(prueth->dev, "could not get rx irq\n"); + goto free; + } + /* get mac address from DT and set private and netdev addr */ ret = of_get_ethdev_address(eth_node, ndev); if (!is_valid_ether_addr(ndev->dev_addr)) { diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index fc59087c214d..3c70dc9c4be0 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -20,6 +20,12 @@ /* PRUSS local memory map */ #define ICSS_LOCAL_SHARED_RAM 0x00010000 +#define EMAC_MAX_PKTLEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) +/* Below macro is for 1528 Byte Frame support, to Allow even with + * Redundancy tag + */ +#define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \ + ICSSM_LRE_TAG_SIZE) /* PRU Ethernet Type - Ethernet functionality (protocol * implemented) provided by the PRU firmware being loaded. @@ -76,6 +82,32 @@ struct prueth_queue_info { u16 buffer_desc_end; } __packed; +/** + * struct prueth_packet_info - Info about a packet in buffer + * @start_offset: start offset of the frame in the buffer for HSR/PRP + * @shadow: this packet is stored in the collision queue + * @port: port packet is on + * @length: length of packet + * @broadcast: this packet is a broadcast packet + * @error: this packet has an error + * @sv_frame: indicate if the frame is a SV frame for HSR/PRP + * @lookup_success: src mac found in FDB + * @flood: packet is to be flooded + * @timestamp: Specifies if timestamp is appended to the packet + */ +struct prueth_packet_info { + bool start_offset; + bool shadow; + unsigned int port; + unsigned int length; + bool broadcast; + bool error; + bool sv_frame; + bool lookup_success; + bool flood; + bool timestamp; +}; + /* In switch mode there are 3 real ports i.e. 3 mac addrs. * however Linux sees only the host side port. The other 2 ports * are the switch ports. @@ -169,14 +201,21 @@ struct prueth_emac { struct rproc *pru; struct phy_device *phydev; + struct prueth_queue_desc __iomem *rx_queue_descs; + struct prueth_queue_desc __iomem *tx_queue_descs; int link; int speed; int duplex; + int rx_irq; + enum prueth_port_queue_id tx_port_queue; + enum prueth_queue_id rx_queue_start; + enum prueth_queue_id rx_queue_end; enum prueth_port port_id; enum prueth_mem dram; const char *phy_id; + u32 msg_enable; u8 mac_addr[6]; phy_interface_t phy_if; spinlock_t lock; /* serialize access */ @@ -201,4 +240,10 @@ struct prueth { size_t ocmc_ram_size; u8 emac_configured; }; + +void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, + struct prueth_packet_info *pkt_info); +int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, + struct prueth_packet_info *pkt_info, + const struct prueth_queue_info *rxqueue); #endif /* __NET_TI_PRUETH_H */ From patchwork Fri Feb 14 07:37:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974575 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 772DFC02198 for ; Fri, 14 Feb 2025 07:41:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=OMoBqNaz0fPePKfZxUIiiCk90IfJa1E938UqvqGzDk4=; b=QQLpE+OEArnHGOMLZTXYN7jB94 0MKi2ApD03XCICbYgrXddo1WFqOUMlx/PCIvUFVcMuJT+0xkZzJr8ADGIJOnW1X4806CPDWtWxfHo JG5h1Jc55h7dj/Tx+HJgZS6NxahxrwQMx59+HoDT83WfunOLzTuxExll1jeQT14MdZQKZ33g8XIjc SwGCLJBTZ9VWzOLe4eC7HJAQVd4eZbX70o+IMw+GhHtQnaIN3oJXg2QaOVXOUSIatJ1KgeezZytyh ARIWUwh6lFkIqT+sFw232i4oigrpEJVKhYQ4QXClPI1VwSiXJDevz8d1Oud1/a8aoC5HqHNzrDUvi 3KM/i5Tg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiqKU-0000000DzMv-3KWm; Fri, 14 Feb 2025 07:41:42 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tiqHs-0000000DynV-41pO for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 07:39:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=OMoBqNaz0fPePKfZxUIiiCk90IfJa1E938UqvqGzDk4=; b=0pkQWz5vxZ+CFWonVsK3bf/4XL 1oA+9xShfe6lRfcHo0OJt7h4A+G3z/QJBRxwXRqJjwwOj1BphAFrHu5vnlVt3/qPaZJ/7S9KF5aH7 lZRlpfVzYZW47qNiwS/ckqi9Lc6NHxIO1+kBWNqYkNkvpOG95H0iVQZgWtLJQuAj6y2HAJ6Z+Xo0r /9JG0NoJPnj0OPje6ZEKMDXrzuuYmJ+9RqDB03oGEGpkj14+zOLfcIOHGr5oA1+2I4XaMXFVhDopE C8hO+Mrlb1ENz7L0MJhL8E1dt4x/6/aYPTJAP6T4XW5HNrKw6aa1gxIUpcW8pEikAPEq2xWNy/TBO XRyVniIQ==; Received: from [122.175.9.182] (port=52498 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tiqHo-0003eJ-30; Fri, 14 Feb 2025 13:08:57 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 05/10] net: ti: prueth: Adds ethtool support for ICSSM PRUETH Driver Date: Fri, 14 Feb 2025 13:07:52 +0530 Message-Id: <20250214073757.1076778-6-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_233901_054578_7AD22DD8 X-CRM114-Status: GOOD ( 19.36 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Changes for enabling ethtool support for the newly added PRU Ethernet interfaces. Extends the support for statistics collection from PRU internal memory and displays it in the user space. Along with statistics, enable/disable of features, configuring link speed etc.are now supported. The firmware running on PRU maintains statistics in internal data memory. When requested ethtool collects all the statistics for the specified interface and displays it in the user space. Makefile is updated to include ethtool support into PRUETH driver. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/Makefile | 2 +- drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 257 ++++++++++++++++++ drivers/net/ethernet/ti/icssm/icssm_prueth.c | 34 +++ drivers/net/ethernet/ti/icssm/icssm_prueth.h | 127 +++++++++ 4 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_ethtool.c diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 93c0a4d0e33a..f21dd11118ab 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o -icssm-prueth-y := icssm/icssm_prueth.o +icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_ethtool.o obj-$(CONFIG_TI_CPSW) += cpsw-common.o obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c new file mode 100644 index 000000000000..85c7afb9557a --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments ICSSM Ethernet Driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#include +#include +#include "icssm_prueth.h" + +#define PRUETH_MODULE_VERSION "0.2" +#define PRUETH_MODULE_DESCRIPTION "PRUSS Ethernet driver" + +/* set PRU firmware statistics */ +void icssm_emac_set_stats(struct prueth_emac *emac, + struct port_statistics *pstats) +{ + void __iomem *dram; + + dram = emac->prueth->mem[emac->dram].va; + memcpy_toio(dram + STATISTICS_OFFSET, pstats, STAT_SIZE); +} + +/* get statistics maintained by the PRU firmware into @pstats */ +void icssm_emac_get_stats(struct prueth_emac *emac, + struct port_statistics *pstats) +{ + void __iomem *dram; + + dram = emac->prueth->mem[emac->dram].va; + memcpy_fromio(pstats, dram + STATISTICS_OFFSET, STAT_SIZE); +} + +/** + * icssm_emac_get_drvinfo - Get EMAC driver information + * @ndev: The network adapter + * @info: ethtool info structure containing name and version + * + * Returns EMAC driver information (name and version) + */ +static void icssm_emac_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strscpy(info->driver, PRUETH_MODULE_DESCRIPTION, sizeof(info->driver)); + strscpy(info->version, PRUETH_MODULE_VERSION, sizeof(info->version)); +} + +/** + * icssm_emac_get_link_ksettings - Get EMAC settings + * @ndev: The network adapter + * @ecmd: ethtool command + * + * Executes ethool get command + * + * Return: 0 (Success) + */ +static int icssm_emac_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *ecmd) +{ + return phy_ethtool_get_link_ksettings(ndev, ecmd); +} + +/** + * icssm_emac_set_link_ksettings - Set EMAC settings + * @ndev: The EMAC network adapter + * @ecmd: ethtool command + * + * Executes ethool set command + * + * Return: 0 (Success) + */ +static int +icssm_emac_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *ecmd) +{ + return phy_ethtool_set_link_ksettings(ndev, ecmd); +} + +#define PRUETH_STAT_OFFSET(m) offsetof(struct port_statistics, m) + +static const struct { + char string[ETH_GSTRING_LEN]; + u32 offset; +} prueth_ethtool_stats[] = { + {"txBcast", PRUETH_STAT_OFFSET(tx_bcast)}, + {"txMcast", PRUETH_STAT_OFFSET(tx_mcast)}, + {"txUcast", PRUETH_STAT_OFFSET(tx_ucast)}, + {"txOctets", PRUETH_STAT_OFFSET(tx_octets)}, + {"rxBcast", PRUETH_STAT_OFFSET(rx_bcast)}, + {"rxMcast", PRUETH_STAT_OFFSET(rx_mcast)}, + {"rxUcast", PRUETH_STAT_OFFSET(rx_ucast)}, + {"rxOctets", PRUETH_STAT_OFFSET(rx_octets)}, + + {"tx64byte", PRUETH_STAT_OFFSET(tx64byte)}, + {"tx65_127byte", PRUETH_STAT_OFFSET(tx65_127byte)}, + {"tx128_255byte", PRUETH_STAT_OFFSET(tx128_255byte)}, + {"tx256_511byte", PRUETH_STAT_OFFSET(tx256_511byte)}, + {"tx512_1023byte", PRUETH_STAT_OFFSET(tx512_1023byte)}, + {"tx1024byte", PRUETH_STAT_OFFSET(tx1024byte)}, + {"rx64byte", PRUETH_STAT_OFFSET(rx64byte)}, + {"rx65_127byte", PRUETH_STAT_OFFSET(rx65_127byte)}, + {"rx128_255byte", PRUETH_STAT_OFFSET(rx128_255byte)}, + {"rx256_511byte", PRUETH_STAT_OFFSET(rx256_511byte)}, + {"rx512_1023byte", PRUETH_STAT_OFFSET(rx512_1023byte)}, + {"rx1024byte", PRUETH_STAT_OFFSET(rx1024byte)}, + + {"lateColl", PRUETH_STAT_OFFSET(late_coll)}, + {"singleColl", PRUETH_STAT_OFFSET(single_coll)}, + {"multiColl", PRUETH_STAT_OFFSET(multi_coll)}, + {"excessColl", PRUETH_STAT_OFFSET(excess_coll)}, + + {"rxMisAlignmentFrames", PRUETH_STAT_OFFSET(rx_misalignment_frames)}, + {"stormPrevCounterBC", PRUETH_STAT_OFFSET(stormprev_counter_bc)}, + {"stormPrevCounterMC", PRUETH_STAT_OFFSET(stormprev_counter_mc)}, + {"stormPrevCounterUC", PRUETH_STAT_OFFSET(stormprev_counter_uc)}, + {"macRxError", PRUETH_STAT_OFFSET(mac_rxerror)}, + {"SFDError", PRUETH_STAT_OFFSET(sfd_error)}, + {"defTx", PRUETH_STAT_OFFSET(def_tx)}, + {"macTxError", PRUETH_STAT_OFFSET(mac_txerror)}, + {"rxOverSizedFrames", PRUETH_STAT_OFFSET(rx_oversized_frames)}, + {"rxUnderSizedFrames", PRUETH_STAT_OFFSET(rx_undersized_frames)}, + {"rxCRCFrames", PRUETH_STAT_OFFSET(rx_crc_frames)}, + {"droppedPackets", PRUETH_STAT_OFFSET(dropped_packets)}, + + {"txHWQOverFlow", PRUETH_STAT_OFFSET(tx_hwq_overflow)}, + {"txHWQUnderFlow", PRUETH_STAT_OFFSET(tx_hwq_underflow)}, + {"vlanDropped", PRUETH_STAT_OFFSET(vlan_dropped)}, + {"multicastDropped", PRUETH_STAT_OFFSET(multicast_dropped)}, +}; + +static int icssm_emac_get_sset_count(struct net_device *ndev, int stringset) +{ + int a_size; + + switch (stringset) { + case ETH_SS_STATS: + a_size = ARRAY_SIZE(prueth_ethtool_stats); + + return a_size; + default: + return -EOPNOTSUPP; + } +} + +static void icssm_emac_get_strings(struct net_device *ndev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(prueth_ethtool_stats); i++) { + memcpy(p, prueth_ethtool_stats[i].string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + default: + break; + } +} + +static void icssm_emac_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct port_statistics pstats; + void *ptr; + u32 val; + int i; + + icssm_emac_get_stats(emac, &pstats); + + for (i = 0; i < ARRAY_SIZE(prueth_ethtool_stats); i++) { + ptr = &pstats; + ptr += prueth_ethtool_stats[i].offset; + val = *(u32 *)ptr; + data[i] = val; + } +} + +static void icssm_emac_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *p) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + + regs->version = PRUETH_REG_DUMP_GET_VER(prueth); +} + +static const struct ethtool_rmon_hist_range icssm_emac_rmon_ranges[] = { + { 0, 64}, + { 65, 127}, + { 128, 255}, + { 256, 511}, + { 512, 1023}, + { 1024, EMAC_MAX_PKTLEN}, + {} +}; + +static void +icssm_emac_get_rmon_stats(struct net_device *ndev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct port_statistics pstats; + + *ranges = icssm_emac_rmon_ranges; + icssm_emac_get_stats(emac, &pstats); + + rmon_stats->undersize_pkts = pstats.rx_undersized_frames; + rmon_stats->oversize_pkts = pstats.rx_oversized_frames; + + rmon_stats->hist[0] = pstats.tx64byte; + rmon_stats->hist[1] = pstats.tx65_127byte; + rmon_stats->hist[2] = pstats.tx128_255byte; + rmon_stats->hist[3] = pstats.tx256_511byte; + rmon_stats->hist[4] = pstats.tx512_1023byte; + + rmon_stats->hist_tx[0] = pstats.rx64byte; + rmon_stats->hist_tx[1] = pstats.rx65_127byte; + rmon_stats->hist_tx[2] = pstats.rx128_255byte; + rmon_stats->hist_tx[3] = pstats.rx256_511byte; + rmon_stats->hist_tx[4] = pstats.rx1024byte; +} + +static void +icssm_emac_get_eth_mac_stats(struct net_device *ndev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct port_statistics pstats; + + icssm_emac_get_stats(emac, &pstats); + + mac_stats->LateCollisions = pstats.late_coll; + mac_stats->SingleCollisionFrames = pstats.single_coll; + mac_stats->MultipleCollisionFrames = pstats.multi_coll; +} + +/* Ethtool support for EMAC adapter */ +const struct ethtool_ops emac_ethtool_ops = { + .get_drvinfo = icssm_emac_get_drvinfo, + .get_link_ksettings = icssm_emac_get_link_ksettings, + .set_link_ksettings = icssm_emac_set_link_ksettings, + .get_link = ethtool_op_get_link, + .get_sset_count = icssm_emac_get_sset_count, + .get_strings = icssm_emac_get_strings, + .get_ethtool_stats = icssm_emac_get_ethtool_stats, + .get_regs = icssm_emac_get_regs, + .get_rmon_stats = icssm_emac_get_rmon_stats, + .get_eth_mac_stats = icssm_emac_get_eth_mac_stats, +}; +EXPORT_SYMBOL_GPL(emac_ethtool_ops); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index 782c0650ac57..736a4ff72167 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -903,6 +903,8 @@ static int icssm_emac_ndo_open(struct net_device *ndev) icssm_prueth_emac_config(emac); + icssm_emac_set_stats(emac, &emac->stats); + ret = icssm_emac_set_boot_pru(emac, ndev); if (ret) return ret; @@ -954,6 +956,8 @@ static int icssm_emac_ndo_stop(struct net_device *ndev) /* stop the PRU */ rproc_shutdown(emac->pru); + icssm_emac_get_stats(emac, &emac->stats); + /* free rx interrupts */ free_irq(emac->rx_irq, ndev); @@ -1047,10 +1051,39 @@ static enum netdev_tx icssm_emac_ndo_start_xmit(struct sk_buff *skb, return ret; } +/** + * icssm_emac_ndo_get_stats64 - EMAC get statistics function + * @ndev: The EMAC network adapter + * @stats: rtnl_link_stats structure + * + * Called when system wants to get statistics from the device. + * + */ +static void icssm_emac_ndo_get_stats64(struct net_device *ndev, + struct rtnl_link_stats64 *stats) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct port_statistics pstats; + + icssm_emac_get_stats(emac, &pstats); + + stats->rx_packets = ndev->stats.rx_packets; + stats->rx_bytes = ndev->stats.rx_bytes; + stats->tx_packets = ndev->stats.tx_packets; + stats->tx_bytes = ndev->stats.tx_bytes; + stats->tx_errors = ndev->stats.tx_errors; + stats->tx_dropped = ndev->stats.tx_dropped; + stats->multicast = pstats.rx_mcast; + + stats->rx_over_errors = ndev->stats.rx_over_errors; + stats->rx_length_errors = ndev->stats.rx_length_errors; +} + static const struct net_device_ops emac_netdev_ops = { .ndo_open = icssm_emac_ndo_open, .ndo_stop = icssm_emac_ndo_stop, .ndo_start_xmit = icssm_emac_ndo_start_xmit, + .ndo_get_stats64 = icssm_emac_ndo_get_stats64, }; /* get emac_port corresponding to eth_node name */ @@ -1179,6 +1212,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); ndev->netdev_ops = &emac_netdev_ops; + ndev->ethtool_ops = &emac_ethtool_ops; return 0; free: diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 3c70dc9c4be0..39ceed0e2d15 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -27,6 +27,12 @@ #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \ ICSSM_LRE_TAG_SIZE) +#define PRUETH_REG_DUMP_VER 1 + +/* Encoding: 32-16: Reserved, 16-8: Reg dump version, 8-0: Ethertype */ +#define PRUETH_REG_DUMP_GET_VER(x) ((PRUETH_REG_DUMP_VER << 8) | \ + ((x)->eth_type)) + /* PRU Ethernet Type - Ethernet functionality (protocol * implemented) provided by the PRU firmware being loaded. */ @@ -108,6 +114,119 @@ struct prueth_packet_info { bool timestamp; }; +/** + * struct port_statistics - Statistics structure for capturing statistics + * on PRUs + * @tx_bcast: Number of broadcast packets sent + * @tx_mcast:Number of multicast packets sent + * @tx_ucast:Number of unicast packets sent + * + * @tx_octets:Number of undersized frames rcvd + * + * @rx_bcast:Number of broadcast packets rcvd + * @rx_mcast:Number of multicast packets rcvd + * @rx_ucast:Number of unicast packets rcvd + * + * @rx_octets:Number of Rx packets + * + * @tx64byte:Number of 64 byte packets sent + * @tx65_127byte:Number of 65-127 byte packets sent + * @tx128_255byte:Number of 128-255 byte packets sent + * @tx256_511byte:Number of 256-511 byte packets sent + * @tx512_1023byte:Number of 512-1023 byte packets sent + * @tx1024byte:Number of 1024 and larger size packets sent + * + * @rx64byte:Number of 64 byte packets rcvd + * @rx65_127byte:Number of 65-127 byte packets rcvd + * @rx128_255byte:Number of 128-255 byte packets rcvd + * @rx256_511byte:Number of 256-511 byte packets rcvd + * @rx512_1023byte:Number of 512-1023 byte packets rcvd + * @rx1024byte:Number of 1024 and larger size packets rcvd + * + * @late_coll:Number of late collisions(Half Duplex) + * @single_coll:Number of single collisions (Half Duplex) + * @multi_coll:Number of multiple collisions (Half Duplex) + * @excess_coll:Number of excess collisions(Half Duplex) + * + * @rx_misalignment_frames:Number of non multiple of 8 byte frames rcvd + * @stormprev_counter:Number of packets dropped because of Storm Prevention + * @mac_rxerror:Number of MAC receive errors + * @sfd_error:Number of invalid SFD + * @def_tx:Number of transmissions deferred + * @mac_txerror:Number of MAC transmit errors + * @rx_oversized_frames:Number of oversized frames rcvd + * @rx_undersized_frames:Number of undersized frames rcvd + * @rx_crc_frames:Number of CRC error frames rcvd + * @dropped_packets:Number of packets dropped due to link down on opposite port + * + * @tx_hwq_overflow:Hardware Tx Queue (on PRU) over flow count + * @tx_hwq_underflow:Hardware Tx Queue (on PRU) under flow count + * + * @u32 cs_error: Number of carrier sense errors + * @sqe_test_error: Number of MAC receive errors + * + * Above fields are aligned so that it's consistent + * with the memory layout in PRU DRAM, this is to facilitate easy + * memcpy. Don't change the order of the fields. + * + * @vlan_dropped: Number of VLAN tagged packets dropped + * @multicast_dropped: Number of multicast packets dropped + */ +struct port_statistics { + u32 tx_bcast; + u32 tx_mcast; + u32 tx_ucast; + + u32 tx_octets; + + u32 rx_bcast; + u32 rx_mcast; + u32 rx_ucast; + + u32 rx_octets; + + u32 tx64byte; + u32 tx65_127byte; + u32 tx128_255byte; + u32 tx256_511byte; + u32 tx512_1023byte; + u32 tx1024byte; + + u32 rx64byte; + u32 rx65_127byte; + u32 rx128_255byte; + u32 rx256_511byte; + u32 rx512_1023byte; + u32 rx1024byte; + + u32 late_coll; + u32 single_coll; + u32 multi_coll; + u32 excess_coll; + + u32 rx_misalignment_frames; + u32 stormprev_counter_bc; + u32 stormprev_counter_mc; + u32 stormprev_counter_uc; + u32 mac_rxerror; + u32 sfd_error; + u32 def_tx; + u32 mac_txerror; + u32 rx_oversized_frames; + u32 rx_undersized_frames; + u32 rx_crc_frames; + u32 dropped_packets; + + u32 tx_hwq_overflow; + u32 tx_hwq_underflow; + + u32 cs_error; + u32 sqe_test_error; + + u32 vlan_dropped; + u32 multicast_dropped; +} __packed; + /* In switch mode there are 3 real ports i.e. 3 mac addrs. * however Linux sees only the host side port. The other 2 ports * are the switch ports. @@ -203,6 +322,7 @@ struct prueth_emac { struct phy_device *phydev; struct prueth_queue_desc __iomem *rx_queue_descs; struct prueth_queue_desc __iomem *tx_queue_descs; + struct port_statistics stats; /* stats holder when i/f is down */ int link; int speed; @@ -241,9 +361,16 @@ struct prueth { u8 emac_configured; }; +extern const struct ethtool_ops emac_ethtool_ops; + void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, struct prueth_packet_info *pkt_info); int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, struct prueth_packet_info *pkt_info, const struct prueth_queue_info *rxqueue); + +void icssm_emac_set_stats(struct prueth_emac *emac, + struct port_statistics *pstats); +void icssm_emac_get_stats(struct prueth_emac *emac, + struct port_statistics *pstats); #endif /* __NET_TI_PRUETH_H */ From patchwork Fri Feb 14 07:37:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974576 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DADC7C02198 for ; Fri, 14 Feb 2025 07:43:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=pZrLNvMS+K3ewdylgdl5oyOqO2i/nXEBXz5XlmyRkFg=; b=mKJtB72O9AKc5Y1YlM61Mp0RUB t8gg9FMRsxvmhEIDz1ZQjUX8lDc+1aJkEU6xmPl9AGYOn3TgcdUa3fqJGkcETS8+Q8lMAIwNLq7+M XS4/bZs0VIRHAmwjwVL4h+3eYUm2+HpNYyNaDy9pX/EC76UVpkLJuSIUsivxeNQAbvSWu9nDork+5 7jEsH6iI4FsOjgipyLtY2Gi2PGsrLu0lcPaqErTY8Aur/7+B2ID6CkGT3q9tBsUHLY0u2T7idF++l lMJxWD/uysjtdlQEe79ay6TOM4+5appxiACNAEiUbAUdqBDTbfrq3Ob+B4dktZtvmLOauqWHJXPQU sbgy8f2w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiqLu-0000000DzeP-20rk; Fri, 14 Feb 2025 07:43:10 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tiqI8-0000000DyrE-3vKy for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 07:39:18 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=pZrLNvMS+K3ewdylgdl5oyOqO2i/nXEBXz5XlmyRkFg=; b=1X2X+paGklmsWCBMN6NNlAiHo7 Yl3M++baj6PAU3Un4krxbeb6YPYPhmxffoTZ7toXLN01OeGd5T2N7qUqNgcXeemKtjP++QUck0FWN XAgyBO2l38Y6WbDmcM/mnXGTWbSWmQZiUG04qJlTmXi83Lx/++snuHLjFsCa7rTP0u3j64w0eSuxD YF2nt4PVXeRD27eE+Aho7La5Am7PU+au9h7dvgZDIIi3uOJTtJAOu4zngACbunMsyL5noZPWGmwHT haJwm+zIhsJuXPfcaYVdF0f3p400mYjSAs+KQI+K6KJnqKdRUR6Z3fiIqv3OfSS4FY8Hz7j8oVQgT YURHVFBg==; Received: from [122.175.9.182] (port=52498 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tiqI4-0003eJ-2Z; Fri, 14 Feb 2025 13:09:12 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 06/10] net: ti: prueth: Adds HW timestamping support for PTP using PRU-ICSS IEP module Date: Fri, 14 Feb 2025 13:07:53 +0530 Message-Id: <20250214073757.1076778-7-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_233917_051529_E521E11F X-CRM114-Status: GOOD ( 24.33 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros PRU-ICSS IEP module, which is capable of timestamping RX and TX packets at HW level, is used for time synchronization by PTP4L. This change includes interaction between firmware and user space application (ptp4l) with required packet timestamps. The driver initializes the PRU firmware with appropriate mode and configuration flags. Firmware updates local registers with the flags set by driver and uses for further operation. RX SOF timestamp comes along with packet and firmware will rise interrupt with TX SOF timestamp after pushing the packet on to the wire. IEP driver is available in upstream and we are reusing for hardware configuration for ICSSM as well. On top of that we have extended it with the changes for AM57xx SoC. Extended ethtool for reading HW timestamping capability of the PRU interfaces. Currently ordinary clock (OC) configuration has been validated with Linux ptp4l. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/icssg/icss_iep.c | 42 ++ drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 23 + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 444 +++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 11 + .../net/ethernet/ti/icssm/icssm_prueth_ptp.h | 85 ++++ 5 files changed, 603 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c index 768578c0d958..9a2ea13703d8 100644 --- a/drivers/net/ethernet/ti/icssg/icss_iep.c +++ b/drivers/net/ethernet/ti/icssg/icss_iep.c @@ -937,11 +937,53 @@ static const struct icss_iep_plat_data am654_icss_iep_plat_data = { .config = &am654_icss_iep_regmap_config, }; +static const struct icss_iep_plat_data am57xx_icss_iep_plat_data = { + .flags = ICSS_IEP_64BIT_COUNTER_SUPPORT | + ICSS_IEP_SLOW_COMPEN_REG_SUPPORT, + .reg_offs = { + [ICSS_IEP_GLOBAL_CFG_REG] = 0x00, + [ICSS_IEP_COMPEN_REG] = 0x08, + [ICSS_IEP_SLOW_COMPEN_REG] = 0x0C, + [ICSS_IEP_COUNT_REG0] = 0x10, + [ICSS_IEP_COUNT_REG1] = 0x14, + [ICSS_IEP_CAPTURE_CFG_REG] = 0x18, + [ICSS_IEP_CAPTURE_STAT_REG] = 0x1c, + + [ICSS_IEP_CAP6_RISE_REG0] = 0x50, + [ICSS_IEP_CAP6_RISE_REG1] = 0x54, + + [ICSS_IEP_CAP7_RISE_REG0] = 0x60, + [ICSS_IEP_CAP7_RISE_REG1] = 0x64, + + [ICSS_IEP_CMP_CFG_REG] = 0x70, + [ICSS_IEP_CMP_STAT_REG] = 0x74, + [ICSS_IEP_CMP0_REG0] = 0x78, + [ICSS_IEP_CMP0_REG1] = 0x7c, + [ICSS_IEP_CMP1_REG0] = 0x80, + [ICSS_IEP_CMP1_REG1] = 0x84, + + [ICSS_IEP_CMP8_REG0] = 0xc0, + [ICSS_IEP_CMP8_REG1] = 0xc4, + [ICSS_IEP_SYNC_CTRL_REG] = 0x180, + [ICSS_IEP_SYNC0_STAT_REG] = 0x188, + [ICSS_IEP_SYNC1_STAT_REG] = 0x18c, + [ICSS_IEP_SYNC_PWIDTH_REG] = 0x190, + [ICSS_IEP_SYNC0_PERIOD_REG] = 0x194, + [ICSS_IEP_SYNC1_DELAY_REG] = 0x198, + [ICSS_IEP_SYNC_START_REG] = 0x19c, + }, + .config = &am654_icss_iep_regmap_config, +}; + static const struct of_device_id icss_iep_of_match[] = { { .compatible = "ti,am654-icss-iep", .data = &am654_icss_iep_plat_data, }, + { + .compatible = "ti,am5728-icss-iep", + .data = &am57xx_icss_iep_plat_data, + }, {}, }; MODULE_DEVICE_TABLE(of, icss_iep_of_match); diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c index 85c7afb9557a..2d92d142c08c 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -8,6 +8,7 @@ #include #include #include "icssm_prueth.h" +#include "../icssg/icss_iep.h" #define PRUETH_MODULE_VERSION "0.2" #define PRUETH_MODULE_DESCRIPTION "PRUSS Ethernet driver" @@ -241,6 +242,27 @@ icssm_emac_get_eth_mac_stats(struct net_device *ndev, mac_stats->MultipleCollisionFrames = pstats.multi_coll; } +static int icssm_emac_get_ts_info(struct net_device *ndev, + struct kernel_ethtool_ts_info *info) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + if ((PRUETH_IS_EMAC(emac->prueth) && !emac->emac_ptp_tx_irq)) + return ethtool_op_get_ts_info(ndev, info); + + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->phc_index = icss_iep_get_ptp_clock_idx(emac->prueth->iep); + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); + + return 0; +} + /* Ethtool support for EMAC adapter */ const struct ethtool_ops emac_ethtool_ops = { .get_drvinfo = icssm_emac_get_drvinfo, @@ -253,5 +275,6 @@ const struct ethtool_ops emac_ethtool_ops = { .get_regs = icssm_emac_get_regs, .get_rmon_stats = icssm_emac_get_rmon_stats, .get_eth_mac_stats = icssm_emac_get_eth_mac_stats, + .get_ts_info = icssm_emac_get_ts_info, }; EXPORT_SYMBOL_GPL(emac_ethtool_ops); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index 736a4ff72167..f9c970c7c016 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -30,6 +30,7 @@ #include "icssm_prueth.h" #include "../icssg/icssg_mii_rt.h" +#include "../icssg/icss_iep.h" #define OCMC_RAM_SIZE (SZ_64K) @@ -50,6 +51,45 @@ static inline void icssm_prueth_write_reg(struct prueth *prueth, ETH_FCS_LEN + \ ICSSM_LRE_TAG_SIZE) +static inline void icssm_prueth_ptp_ts_enable(struct prueth_emac *emac) +{ + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + u8 val = 0; + + if (emac->ptp_tx_enable) { + /* Disable fw background task */ + val &= ~TIMESYNC_CTRL_BG_ENABLE; + /* Enable forced 2-step */ + val |= TIMESYNC_CTRL_FORCED_2STEP; + } + + writeb(val, sram + TIMESYNC_CTRL_VAR_OFFSET); +} + +static inline void icssm_prueth_ptp_tx_ts_enable(struct prueth_emac *emac, + bool enable) +{ + emac->ptp_tx_enable = enable; + icssm_prueth_ptp_ts_enable(emac); +} + +static inline bool icssm_prueth_ptp_tx_ts_is_enabled(struct prueth_emac *emac) +{ + return !!emac->ptp_tx_enable; +} + +static inline void icssm_prueth_ptp_rx_ts_enable(struct prueth_emac *emac, + bool enable) +{ + emac->ptp_rx_enable = enable; + icssm_prueth_ptp_ts_enable(emac); +} + +static inline bool icssm_prueth_ptp_rx_ts_is_enabled(struct prueth_emac *emac) +{ + return !!emac->ptp_rx_enable; +} + /* ensure that order of PRUSS mem regions is same as enum prueth_mem */ static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1, PRUSS_MEM_SHRD_RAM2 }; @@ -466,6 +506,173 @@ static void icssm_get_block(struct prueth_queue_desc __iomem *queue_desc, queue->buffer_desc_offset) / BD_SIZE; } +static u8 icssm_prueth_ptp_ts_event_type(struct sk_buff *skb, u8 *ptp_msgtype) +{ + unsigned int ptp_class = ptp_classify_raw(skb); + struct ptp_header *hdr; + u8 msgtype, event_type; + + if (ptp_class == PTP_CLASS_NONE) + return PRUETH_PTP_TS_EVENTS; + + hdr = ptp_parse_header(skb, ptp_class); + if (!hdr) + return PRUETH_PTP_TS_EVENTS; + + msgtype = ptp_get_msgtype(hdr, ptp_class); + /* Treat E2E Delay Req/Resp messages in the same way as P2P peer delay + * req/resp in driver here since firmware stores timestamps in the same + * memory location for either (since they cannot operate simultaneously + * anyway) + */ + switch (msgtype) { + case PTP_MSGTYPE_SYNC: + event_type = PRUETH_PTP_SYNC; + break; + case PTP_MSGTYPE_DELAY_REQ: + case PTP_MSGTYPE_PDELAY_REQ: + event_type = PRUETH_PTP_DLY_REQ; + break; + /* TODO: Check why PTP_MSGTYPE_DELAY_RESP needs timestamp + * and need for it. + */ + case 0x9: + case PTP_MSGTYPE_PDELAY_RESP: + event_type = PRUETH_PTP_DLY_RESP; + break; + default: + event_type = PRUETH_PTP_TS_EVENTS; + } + + if (ptp_msgtype) + *ptp_msgtype = msgtype; + + return event_type; +} + +static void icssm_prueth_ptp_tx_ts_reset(struct prueth_emac *emac, u8 event) +{ + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + u32 ts_notify_offs, ts_offs; + + ts_offs = icssm_prueth_tx_ts_offs_get(emac->port_id - 1, event); + ts_notify_offs = icssm_prueth_tx_ts_notify_offs_get(emac->port_id - 1, + event); + + writeb(0, sram + ts_notify_offs); + memset_io(sram + ts_offs, 0, sizeof(u64)); +} + +static int icssm_prueth_ptp_tx_ts_enqueue(struct prueth_emac *emac, + struct sk_buff *skb) +{ + u8 event, changed = 0; + unsigned long flags; + + if (skb_vlan_tagged(skb)) { + __skb_pull(skb, VLAN_HLEN); + changed += VLAN_HLEN; + } + + skb_reset_mac_header(skb); + event = icssm_prueth_ptp_ts_event_type(skb, NULL); + __skb_push(skb, changed); + if (event == PRUETH_PTP_TS_EVENTS) { + netdev_err(emac->ndev, "invalid PTP event\n"); + return -EINVAL; + } + + spin_lock_irqsave(&emac->ptp_skb_lock, flags); + if (emac->ptp_skb[event]) { + dev_consume_skb_any(emac->ptp_skb[event]); + icssm_prueth_ptp_tx_ts_reset(emac, event); + netdev_warn(emac->ndev, "Dropped event waiting for tx ts.\n"); + } + + skb_get(skb); + emac->ptp_skb[event] = skb; + spin_unlock_irqrestore(&emac->ptp_skb_lock, flags); + + return 0; +} + +irqreturn_t icssm_prueth_ptp_tx_irq_handle(int irq, void *dev) +{ + struct net_device *ndev = (struct net_device *)dev; + struct prueth_emac *emac = netdev_priv(ndev); + + if (unlikely(netif_queue_stopped(ndev))) + netif_wake_queue(ndev); + + if (icssm_prueth_ptp_tx_ts_is_enabled(emac)) + return IRQ_WAKE_THREAD; + + return IRQ_HANDLED; +} + +static u64 icssm_prueth_ptp_ts_get(struct prueth_emac *emac, u32 ts_offs) +{ + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + u64 cycles; + + memcpy_fromio(&cycles, sram + ts_offs, sizeof(cycles)); + memset_io(sram + ts_offs, 0, sizeof(cycles)); + + return cycles; +} + +static void icssm_prueth_ptp_tx_ts_get(struct prueth_emac *emac, u8 event) +{ + struct skb_shared_hwtstamps ssh; + struct sk_buff *skb; + unsigned long flags; + u64 ns; + + /* get the msg from list */ + spin_lock_irqsave(&emac->ptp_skb_lock, flags); + skb = emac->ptp_skb[event]; + emac->ptp_skb[event] = NULL; + spin_unlock_irqrestore(&emac->ptp_skb_lock, flags); + if (!skb) { + netdev_err(emac->ndev, "no tx msg %u found waiting for ts\n", + event); + return; + } + + /* get timestamp */ + ns = icssm_prueth_ptp_ts_get(emac, + icssm_prueth_tx_ts_offs_get + (emac->port_id - 1, event)); + + memset(&ssh, 0, sizeof(ssh)); + ssh.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(skb, &ssh); + dev_consume_skb_any(skb); +} + +irqreturn_t icssm_prueth_ptp_tx_irq_work(int irq, void *dev) +{ + struct prueth_emac *emac = netdev_priv(dev); + u32 ts_notify_offs, ts_notify_mask, i; + void __iomem *sram; + + /* get and reset the ts notifications */ + sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + for (i = 0; i < PRUETH_PTP_TS_EVENTS; i++) { + ts_notify_offs = + icssm_prueth_tx_ts_notify_offs_get(emac->port_id - 1, + i); + memcpy_fromio(&ts_notify_mask, sram + ts_notify_offs, + PRUETH_PTP_TS_NOTIFY_SIZE); + memset_io(sram + ts_notify_offs, 0, PRUETH_PTP_TS_NOTIFY_SIZE); + + if (ts_notify_mask & PRUETH_PTP_TS_NOTIFY_MASK) + icssm_prueth_ptp_tx_ts_get(emac, i); + } + + return IRQ_HANDLED; +} + /** * icssm_prueth_tx_enqueue - queue a packet to firmware for transmission * @@ -570,6 +777,12 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac, memcpy(dst_addr, src_addr, pktlen); } + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && + icssm_prueth_ptp_tx_ts_is_enabled(emac)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + icssm_prueth_ptp_tx_ts_enqueue(emac, skb); + } + /* update first buffer descriptor */ wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) & PRUETH_BD_LENGTH_MASK; @@ -620,6 +833,7 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, const struct prueth_queue_info *rxqueue) { struct net_device *ndev = emac->ndev; + struct skb_shared_hwtstamps *ssh; unsigned int buffer_desc_count; int read_block, update_block; unsigned int actual_pkt_len; @@ -629,6 +843,7 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, struct sk_buff *skb; int pkt_block_size; void *ocmc_ram; + u64 ts = 0; /* the PRU firmware deals mostly in pointers already * offset into ram, we would like to deal in indexes @@ -638,6 +853,8 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, buffer_desc_count = icssm_get_buff_desc_count(rxqueue); read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE; pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE); + if (pkt_info->timestamp) + pkt_block_size++; /* calculate end BD address post read */ update_block = read_block + pkt_block_size; @@ -705,9 +922,22 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, src_addr += actual_pkt_len; } + if (pkt_info->timestamp) { + src_addr = (void *)PTR_ALIGN((uintptr_t)src_addr, + ICSS_BLOCK_SIZE); + dst_addr = &ts; + memcpy(dst_addr, src_addr, sizeof(ts)); + } + if (!pkt_info->sv_frame) { skb_put(skb, actual_pkt_len); + if (icssm_prueth_ptp_rx_ts_is_enabled(emac) && + pkt_info->timestamp) { + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); + ssh->hwtstamp = ns_to_ktime(ts); + } /* send packet up the stack */ skb->protocol = eth_type_trans(skb, ndev); local_bh_disable(); @@ -878,9 +1108,67 @@ static int icssm_emac_request_irqs(struct prueth_emac *emac) return ret; } + if (emac->emac_ptp_tx_irq) { + ret = request_threaded_irq(emac->emac_ptp_tx_irq, + icssm_prueth_ptp_tx_irq_handle, + icssm_prueth_ptp_tx_irq_work, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + ndev->name, ndev); + if (ret) { + netdev_err(ndev, "unable to request PTP TX IRQ\n"); + goto free_irq; + } + } + + return 0; + +free_irq: + free_irq(emac->rx_irq, ndev); return ret; } +static void icssm_iptp_dram_init(struct prueth_emac *emac) +{ + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; + u64 temp64; + + writew(0, sram + MII_RX_CORRECTION_OFFSET); + writew(0, sram + MII_TX_CORRECTION_OFFSET); + + /* Initialize RCF to 1 (Linux N/A) */ + writel(1 * 1024, sram + TIMESYNC_TC_RCF_OFFSET); + + /* This flag will be set and cleared by firmware */ + /* Write Sync0 period for sync signal generation in PTP + * memory in shared RAM + */ + writel(200000000 / 50, sram + TIMESYNC_SYNC0_WIDTH_OFFSET); + + /* Write CMP1 period for sync signal generation in PTP + * memory in shared RAM + */ + temp64 = 1000000; + memcpy_toio(sram + TIMESYNC_CMP1_CMP_OFFSET, &temp64, sizeof(temp64)); + + /* Write Sync0 period for sync signal generation in PTP + * memory in shared RAM + */ + writel(1000000, sram + TIMESYNC_CMP1_PERIOD_OFFSET); + + /* Configures domainNumber list. Firmware supports 2 domains */ + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST); + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST + 1); + + /* Configure 1-step/2-step */ + writeb(1, sram + DISABLE_SWITCH_SYNC_RELAY_OFFSET); + + /* Configures the setting to Link local frame without HSR tag */ + writeb(0, sram + LINK_LOCAL_FRAME_HAS_HSR_TAG); + + /* Enable E2E/UDP PTP message timestamping */ + writeb(1, sram + PTP_IPV4_UDP_E2E_ENABLE); +} + /** * icssm_emac_ndo_open - EMAC device open * @ndev: network adapter device @@ -905,9 +1193,18 @@ static int icssm_emac_ndo_open(struct net_device *ndev) icssm_emac_set_stats(emac, &emac->stats); + if (!prueth->emac_configured) { + icssm_iptp_dram_init(emac); + ret = icss_iep_init(prueth->iep, NULL, NULL, 0); + if (ret) { + netdev_err(ndev, "Failed to initialize iep: %d\n", ret); + goto iep_exit; + } + } + ret = icssm_emac_set_boot_pru(emac, ndev); if (ret) - return ret; + goto iep_exit; ret = icssm_emac_request_irqs(emac); if (ret) @@ -929,6 +1226,10 @@ static int icssm_emac_ndo_open(struct net_device *ndev) rproc_shutdown: rproc_shutdown(emac->pru); +iep_exit: + if (!prueth->emac_configured) + icss_iep_exit(prueth->iep); + return ret; } @@ -944,6 +1245,7 @@ static int icssm_emac_ndo_stop(struct net_device *ndev) { struct prueth_emac *emac = netdev_priv(ndev); struct prueth *prueth = emac->prueth; + int i; prueth->emac_configured &= ~BIT(emac->port_id); @@ -953,13 +1255,32 @@ static int icssm_emac_ndo_stop(struct net_device *ndev) /* stop PHY */ phy_stop(emac->phydev); + /* inform the upper layers. */ + netif_stop_queue(ndev); + /* stop the PRU */ rproc_shutdown(emac->pru); icssm_emac_get_stats(emac, &emac->stats); + /* Cleanup ptp related stuff for all protocols */ + icssm_prueth_ptp_tx_ts_enable(emac, 0); + icssm_prueth_ptp_rx_ts_enable(emac, 0); + for (i = 0; i < PRUETH_PTP_TS_EVENTS; i++) { + if (emac->ptp_skb[i]) { + icssm_prueth_ptp_tx_ts_reset(emac, i); + dev_consume_skb_any(emac->ptp_skb[i]); + emac->ptp_skb[i] = NULL; + } + } + /* free rx interrupts */ free_irq(emac->rx_irq, ndev); + if (emac->emac_ptp_tx_irq) + free_irq(emac->emac_ptp_tx_irq, ndev); + + if (!prueth->emac_configured) + icss_iep_exit(prueth->iep); if (netif_msg_drv(emac)) dev_notice(&ndev->dev, "stopped\n"); @@ -1051,6 +1372,30 @@ static enum netdev_tx icssm_emac_ndo_start_xmit(struct sk_buff *skb, return ret; } +/** + * icssm_emac_ndo_tx_timeout - EMAC Transmit timeout function + * @ndev: The EMAC network adapter + * @txqueue: TX queue being used + * + * Called when system detects that a skb timeout period has expired + * potentially due to a fault in the adapter in not being able to send + * it out on the wire. + */ +static void icssm_emac_ndo_tx_timeout(struct net_device *ndev, + unsigned int txqueue) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + if (netif_msg_tx_err(emac)) + netdev_err(ndev, "xmit timeout"); + + ndev->stats.tx_errors++; + + /* TODO: can we recover or need to reboot firmware? */ + + netif_wake_queue(ndev); +} + /** * icssm_emac_ndo_get_stats64 - EMAC get statistics function * @ndev: The EMAC network adapter @@ -1079,11 +1424,86 @@ static void icssm_emac_ndo_get_stats64(struct net_device *ndev, stats->rx_length_errors = ndev->stats.rx_length_errors; } +static int icssm_emac_hwtstamp_config_set(struct net_device *ndev, + struct ifreq *ifr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct hwtstamp_config cfg; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + /* reserved for future extensions */ + if (cfg.flags) + return -EINVAL; + + if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON) + return -ERANGE; + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: + icssm_prueth_ptp_rx_ts_enable(emac, 0); + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + icssm_prueth_ptp_rx_ts_enable(emac, 1); + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + default: + return -ERANGE; + } + + icssm_prueth_ptp_tx_ts_enable(emac, cfg.tx_type == HWTSTAMP_TX_ON); + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + +static int icssm_emac_hwtstamp_config_get(struct net_device *ndev, + struct ifreq *ifr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct hwtstamp_config cfg; + + cfg.flags = 0; + cfg.tx_type = icssm_prueth_ptp_tx_ts_is_enabled(emac) ? + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + cfg.rx_filter = icssm_prueth_ptp_rx_ts_is_enabled(emac) ? + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + +static int icssm_emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, + int cmd) +{ + switch (cmd) { + case SIOCSHWTSTAMP: + return icssm_emac_hwtstamp_config_set(ndev, ifr); + case SIOCGHWTSTAMP: + return icssm_emac_hwtstamp_config_get(ndev, ifr); + } + + return phy_do_ioctl(ndev, ifr, cmd); +} + static const struct net_device_ops emac_netdev_ops = { .ndo_open = icssm_emac_ndo_open, .ndo_stop = icssm_emac_ndo_stop, .ndo_start_xmit = icssm_emac_ndo_start_xmit, + .ndo_tx_timeout = icssm_emac_ndo_tx_timeout, .ndo_get_stats64 = icssm_emac_ndo_get_stats64, + .ndo_eth_ioctl = icssm_emac_ndo_ioctl, }; /* get emac_port corresponding to eth_node name */ @@ -1184,6 +1604,14 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, goto free; } + emac->emac_ptp_tx_irq = of_irq_get_byname(eth_node, "emac_ptp_tx"); + if (emac->emac_ptp_tx_irq < 0) { + emac->emac_ptp_tx_irq = 0; + dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n"); + } + + spin_lock_init(&emac->ptp_skb_lock); + /* get mac address from DT and set private and netdev addr */ ret = of_get_ethdev_address(eth_node, ndev); if (!is_valid_ether_addr(ndev->dev_addr)) { @@ -1432,12 +1860,19 @@ static int icssm_prueth_probe(struct platform_device *pdev) } } + prueth->iep = icss_iep_get(np); + if (IS_ERR(prueth->iep)) { + ret = PTR_ERR(prueth->iep); + dev_err(dev, "unable to get IEP\n"); + goto netdev_exit; + } + /* register the network devices */ if (eth0_node) { ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); if (ret) { dev_err(dev, "can't register netdev for port MII0"); - goto netdev_exit; + goto iep_put; } prueth->registered_netdevs[PRUETH_MAC0] = @@ -1471,6 +1906,9 @@ static int icssm_prueth_probe(struct platform_device *pdev) unregister_netdev(prueth->registered_netdevs[i]); } +iep_put: + icss_iep_put(prueth->iep); + netdev_exit: for (i = 0; i < PRUETH_NUM_MACS; i++) { eth_node = prueth->eth_node[i]; @@ -1542,6 +1980,8 @@ static void icssm_prueth_remove(struct platform_device *pdev) &prueth->mem[i]); } + icss_iep_put(prueth->iep); + pruss_put(prueth->pruss); if (prueth->eth_node[PRUETH_MAC0]) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 39ceed0e2d15..1709b3b6c2be 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -14,6 +14,7 @@ #include #include "icssm_switch.h" +#include "icssm_prueth_ptp.h" /* ICSSM size of redundancy tag */ #define ICSSM_LRE_TAG_SIZE 6 @@ -339,6 +340,12 @@ struct prueth_emac { u8 mac_addr[6]; phy_interface_t phy_if; spinlock_t lock; /* serialize access */ + + struct sk_buff *ptp_skb[PRUETH_PTP_TS_EVENTS]; + spinlock_t ptp_skb_lock; /* serialize access */ + int emac_ptp_tx_irq; + bool ptp_tx_enable; + bool ptp_rx_enable; }; struct prueth { @@ -348,6 +355,7 @@ struct prueth { struct pruss_mem_region mem[PRUETH_MEM_MAX]; struct gen_pool *sram_pool; struct regmap *mii_rt; + struct icss_iep *iep; const struct prueth_private_data *fw_data; struct prueth_fw_offsets *fw_offsets; @@ -369,6 +377,9 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, struct prueth_packet_info *pkt_info, const struct prueth_queue_info *rxqueue); +irqreturn_t icssm_prueth_ptp_tx_irq_handle(int irq, void *dev); +irqreturn_t icssm_prueth_ptp_tx_irq_work(int irq, void *dev); + void icssm_emac_set_stats(struct prueth_emac *emac, struct port_statistics *pstats); void icssm_emac_get_stats(struct prueth_emac *emac, diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h new file mode 100644 index 000000000000..e0bf692beda1 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com + */ +#ifndef PRUETH_PTP_H +#define PRUETH_PTP_H + +#define RX_SYNC_TIMESTAMP_OFFSET_P1 0x8 /* 8 bytes */ +#define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x14 /* 12 bytes */ + +#define DISABLE_PTP_FRAME_FORWARDING_CTRL_OFFSET 0x14 /* 1 byte */ + +#define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x20 /* 12 bytes */ +#define RX_SYNC_TIMESTAMP_OFFSET_P2 0x2c /* 12 bytes */ +#define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0x38 /* 12 bytes */ +#define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0x44 /* 12 bytes */ +#define TIMESYNC_DOMAIN_NUMBER_LIST 0x50 /* 2 bytes */ +#define P1_SMA_LINE_DELAY_OFFSET 0x52 /* 4 bytes */ +#define P2_SMA_LINE_DELAY_OFFSET 0x56 /* 4 bytes */ +#define TIMESYNC_SECONDS_COUNT_OFFSET 0x5a /* 6 bytes */ +#define TIMESYNC_TC_RCF_OFFSET 0x60 /* 4 bytes */ +#define DUT_IS_MASTER_OFFSET 0x64 /* 1 byte */ +#define MASTER_PORT_NUM_OFFSET 0x65 /* 1 byte */ +#define SYNC_MASTER_MAC_OFFSET 0x66 /* 6 bytes */ +#define TX_TS_NOTIFICATION_OFFSET_SYNC_P1 0x6c /* 1 byte */ +#define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P1 0x6d /* 1 byte */ +#define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P1 0x6e /* 1 byte */ +#define TX_TS_NOTIFICATION_OFFSET_SYNC_P2 0x6f /* 1 byte */ +#define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P2 0x70 /* 1 byte */ +#define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P2 0x71 /* 1 byte */ +#define TX_SYNC_TIMESTAMP_OFFSET_P1 0x72 /* 12 bytes */ +#define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x7e /* 12 bytes */ +#define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x8a /* 12 bytes */ +#define TX_SYNC_TIMESTAMP_OFFSET_P2 0x96 /* 12 bytes */ +#define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0xa2 /* 12 bytes */ +#define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0xae /* 12 bytes */ +#define TIMESYNC_CTRL_VAR_OFFSET 0xba /* 1 byte */ +#define DISABLE_SWITCH_SYNC_RELAY_OFFSET 0xbb /* 1 byte */ +#define MII_RX_CORRECTION_OFFSET 0xbc /* 2 bytes */ +#define MII_TX_CORRECTION_OFFSET 0xbe /* 2 bytes */ +#define TIMESYNC_CMP1_CMP_OFFSET 0xc0 /* 8 bytes */ +#define TIMESYNC_SYNC0_CMP_OFFSET 0xc8 /* 8 bytes */ +#define TIMESYNC_CMP1_PERIOD_OFFSET 0xd0 /* 4 bytes */ +#define TIMESYNC_SYNC0_WIDTH_OFFSET 0xd4 /* 4 bytes */ +#define SINGLE_STEP_IEP_OFFSET_P1 0xd8 /* 8 bytes */ +#define SINGLE_STEP_SECONDS_OFFSET_P1 0xe0 /* 8 bytes */ +#define SINGLE_STEP_IEP_OFFSET_P2 0xe8 /* 8 bytes */ +#define SINGLE_STEP_SECONDS_OFFSET_P2 0xf0 /* 8 bytes */ +#define LINK_LOCAL_FRAME_HAS_HSR_TAG 0xf8 /* 1 bytes */ +#define PTP_PREV_TX_TIMESTAMP_P1 0xf9 /* 8 bytes */ +#define PTP_PREV_TX_TIMESTAMP_P2 0x101 /* 8 bytes */ +#define PTP_CLK_IDENTITY_OFFSET 0x109 /* 8 bytes */ +#define PTP_SCRATCH_MEM 0x111 /* 16 byte */ +#define PTP_IPV4_UDP_E2E_ENABLE 0x121 /* 1 byte */ + +enum { + PRUETH_PTP_SYNC, + PRUETH_PTP_DLY_REQ, + PRUETH_PTP_DLY_RESP, + PRUETH_PTP_TS_EVENTS, +}; + +#define PRUETH_PTP_TS_SIZE 12 +#define PRUETH_PTP_TS_NOTIFY_SIZE 1 +#define PRUETH_PTP_TS_NOTIFY_MASK 0xff + +/* Bit definitions for TIMESYNC_CTRL */ +#define TIMESYNC_CTRL_BG_ENABLE BIT(0) +#define TIMESYNC_CTRL_FORCED_2STEP BIT(1) + +static inline u32 icssm_prueth_tx_ts_offs_get(u8 port, u8 event) +{ + return TX_SYNC_TIMESTAMP_OFFSET_P1 + port * + PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_SIZE + + event * PRUETH_PTP_TS_SIZE; +} + +static inline u32 icssm_prueth_tx_ts_notify_offs_get(u8 port, u8 event) +{ + return TX_TS_NOTIFICATION_OFFSET_SYNC_P1 + + PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_NOTIFY_SIZE * port + + event * PRUETH_PTP_TS_NOTIFY_SIZE; +} + +#endif /* PRUETH_PTP_H */ From patchwork Fri Feb 14 07:37:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974577 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 093AFC02198 for ; Fri, 14 Feb 2025 07:44:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=9/g15VLwDOrrrWI1/LXFIFNQo1WQlsSIV3t8+kTT0K0=; b=coT35kdGPGRteGBXkGITVk7eNc +h6cZqwL/ZpwUsW5EIU/BknvhYbudmoXYW3loZxdcYRlEQyyc+IPin1ZhfeAIjW2eJ5dJoFWjSCZv yTTsGZwyxfFNmfVsdskfTozzLn1KGs3FD92Kw26tI0zgHM49MOL99nimQpyQDDK3gWGfIgCmTJBIH OX2UUTAQ5nzuFcfCe3XDRDYDSIzTK5Bu+Fv7VkvO7xE/FmhnjJtUkQW8iwUsJdp+EEuRdA35t5uHO MVIystZsGdMSpqWKPQnm9Py1NDO/fLGyjiVuADBmEpRERTLeisdpcAAGT3FyQdIPrvFZL2jeBh6ub 9Ry9OhUw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tiqNJ-0000000Dzse-0Z4r; Fri, 14 Feb 2025 07:44:37 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tiqIN-0000000Dytb-2oVs for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 07:39:33 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=9/g15VLwDOrrrWI1/LXFIFNQo1WQlsSIV3t8+kTT0K0=; b=WLMSTq381fPtWOCZ0t6uCFuFHN osYLEiQ8CH1AR4Uyc8JGz04EqZNAx9ayewcnhrXFcpZHglNFxaOyC/zMCEibrIyIKrm/w0oZqe/uI /0fRWYPM0OfGtObyLzt+ufh0c47IkVtj/R/mDDWC9sHkrBqCbc3HP2//cCnaqT/DCZhN2A+T21pXN /4L3Vx9MVfZekeCV7IkExK4QVCQLeutjVl6BRNFZ6EDRGum0+IqolfMBNiyz3rFhtHxCElfwudXDq vsVDZPuZ68zB2rVbH27AR3FsN/LFJGvShjY80tYupbTFBPBDb+KoUgEyuQH7YqeoGj3hf3U8mz8FA 2vIWiVHg==; Received: from [122.175.9.182] (port=52498 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tiqIJ-0003eJ-11; Fri, 14 Feb 2025 13:09:27 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 07/10] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS Date: Fri, 14 Feb 2025 13:07:54 +0530 Message-Id: <20250214073757.1076778-8-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250213_233931_772558_AD84673D X-CRM114-Status: GOOD ( 25.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Driver updates to enable/disable network filters and traffic control features supported by the firmware running on PRU-ICSS. Control of the following features are now supported: 1. Promiscuous mode 2. Network Storm prevention 3. Multicast filtering and 4. VLAN filtering Firmware running on PRU-ICSS will go through all these filter checks prior to sending the rx packets to the host. Ethtool or dev ioctl can be used to enable/disable these features from the user space. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/Makefile | 2 +- drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 39 +++ drivers/net/ethernet/ti/icssm/icssm_prueth.c | 310 +++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 49 ++- .../net/ethernet/ti/icssm/icssm_prueth_dos.c | 225 +++++++++++++ drivers/net/ethernet/ti/icssm/icssm_switch.h | 5 + .../ti/icssm/icssm_vlan_mcast_filter_mmap.h | 120 +++++++ 7 files changed, 747 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index f21dd11118ab..852640ce2b15 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o -icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_ethtool.o +icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_ethtool.o icssm/icssm_prueth_dos.o obj-$(CONFIG_TI_CPSW) += cpsw-common.o obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c index 2d92d142c08c..e4b2a0b7d275 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -8,6 +8,7 @@ #include #include #include "icssm_prueth.h" +#include "icssm_vlan_mcast_filter_mmap.h" #include "../icssg/icss_iep.h" #define PRUETH_MODULE_VERSION "0.2" @@ -21,6 +22,11 @@ void icssm_emac_set_stats(struct prueth_emac *emac, dram = emac->prueth->mem[emac->dram].va; memcpy_toio(dram + STATISTICS_OFFSET, pstats, STAT_SIZE); + + writel(pstats->vlan_dropped, dram + + ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET); + writel(pstats->multicast_dropped, dram + + ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET); } /* get statistics maintained by the PRU firmware into @pstats */ @@ -31,6 +37,11 @@ void icssm_emac_get_stats(struct prueth_emac *emac, dram = emac->prueth->mem[emac->dram].va; memcpy_fromio(pstats, dram + STATISTICS_OFFSET, STAT_SIZE); + + pstats->vlan_dropped = + readl(dram + ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET); + pstats->multicast_dropped = + readl(dram + ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET); } /** @@ -182,13 +193,40 @@ static void icssm_emac_get_ethtool_stats(struct net_device *ndev, } } +static int icssm_emac_get_regs_len(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + + /* VLAN Table at the end of the memory map, after MultiCast + * filter region. So VLAN table base + + * size will give the entire size of reg dump in case of + * Dual-EMAC firmware. + */ + if (PRUETH_IS_EMAC(prueth)) { + return ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR + + ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES; + } + + return 0; +} + static void icssm_emac_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) { struct prueth_emac *emac = netdev_priv(ndev); struct prueth *prueth = emac->prueth; + void __iomem *ram; + u8 *reg = p; regs->version = PRUETH_REG_DUMP_GET_VER(prueth); + + /* Dump firmware's VLAN and MC tables */ + if (PRUETH_IS_EMAC(prueth)) { + ram = prueth->mem[emac->dram].va; + memcpy_fromio(reg, ram, icssm_emac_get_regs_len(ndev)); + return; + } } static const struct ethtool_rmon_hist_range icssm_emac_rmon_ranges[] = { @@ -272,6 +310,7 @@ const struct ethtool_ops emac_ethtool_ops = { .get_sset_count = icssm_emac_get_sset_count, .get_strings = icssm_emac_get_strings, .get_ethtool_stats = icssm_emac_get_ethtool_stats, + .get_regs_len = icssm_emac_get_regs_len, .get_regs = icssm_emac_get_regs, .get_rmon_stats = icssm_emac_get_rmon_stats, .get_eth_mac_stats = icssm_emac_get_eth_mac_stats, diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index f9c970c7c016..e8f8fe5795b3 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -29,6 +29,7 @@ #include #include "icssm_prueth.h" +#include "icssm_vlan_mcast_filter_mmap.h" #include "../icssg/icssg_mii_rt.h" #include "../icssg/icss_iep.h" @@ -37,6 +38,26 @@ #define TX_START_DELAY 0x40 #define TX_CLK_DELAY_100M 0x6 +static struct prueth_fw_offsets fw_offsets_v2_1; + +static void icssm_prueth_set_fw_offsets(struct prueth *prueth) +{ + /* Set VLAN/Multicast filter control and table offsets */ + if (PRUETH_IS_EMAC(prueth)) { + prueth->fw_offsets->vlan_ctrl_byte = + ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET; + prueth->fw_offsets->vlan_filter_tbl = + ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR; + + prueth->fw_offsets->mc_ctrl_byte = + ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET; + prueth->fw_offsets->mc_filter_mask = + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET; + prueth->fw_offsets->mc_filter_tbl = + ICSS_EMAC_FW_MULTICAST_FILTER_TABLE; + } +} + static inline void icssm_prueth_write_reg(struct prueth *prueth, enum prueth_mem region, unsigned int reg, u32 val) @@ -343,18 +364,25 @@ static void icssm_prueth_hostinit(struct prueth *prueth) */ static void icssm_prueth_init_ethernet_mode(struct prueth *prueth) { + icssm_prueth_set_fw_offsets(prueth); icssm_prueth_hostinit(prueth); } static void icssm_prueth_port_enable(struct prueth_emac *emac, bool enable) { struct prueth *prueth = emac->prueth; - void __iomem *port_ctrl; + void __iomem *port_ctrl, *vlan_ctrl; + u32 vlan_ctrl_offset; void __iomem *ram; + vlan_ctrl_offset = prueth->fw_offsets->vlan_ctrl_byte; + ram = prueth->mem[emac->dram].va; port_ctrl = ram + PORT_CONTROL_ADDR; writeb(!!enable, port_ctrl); + + vlan_ctrl = ram + vlan_ctrl_offset; + writeb(!!enable, vlan_ctrl); } static int icssm_prueth_emac_config(struct prueth_emac *emac) @@ -1424,6 +1452,174 @@ static void icssm_emac_ndo_get_stats64(struct net_device *ndev, stats->rx_length_errors = ndev->stats.rx_length_errors; } +/* enable/disable MC filter */ +static void icssm_emac_mc_filter_ctrl(struct prueth_emac *emac, bool enable) +{ + struct prueth *prueth = emac->prueth; + void __iomem *mc_filter_ctrl; + void __iomem *ram; + u32 mc_ctrl_byte; + u32 reg; + + ram = prueth->mem[emac->dram].va; + mc_ctrl_byte = prueth->fw_offsets->mc_ctrl_byte; + mc_filter_ctrl = ram + mc_ctrl_byte; + + if (enable) + reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED; + else + reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED; + + writeb(reg, mc_filter_ctrl); +} + +/* reset MC filter bins */ +static void icssm_emac_mc_filter_reset(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + void __iomem *mc_filter_tbl; + u32 mc_filter_tbl_base; + void __iomem *ram; + + ram = prueth->mem[emac->dram].va; + mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl; + + mc_filter_tbl = ram + mc_filter_tbl_base; + memset_io(mc_filter_tbl, 0, ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES); +} + +/* set MC filter hashmask */ +static void icssm_emac_mc_filter_hashmask + (struct prueth_emac *emac, + u8 mask[ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES]) +{ + struct prueth *prueth = emac->prueth; + void __iomem *mc_filter_mask; + u32 mc_filter_mask_base; + void __iomem *ram; + + ram = prueth->mem[emac->dram].va; + mc_filter_mask_base = prueth->fw_offsets->mc_filter_mask; + + mc_filter_mask = ram + mc_filter_mask_base; + memcpy_toio(mc_filter_mask, mask, + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES); +} + +static void icssm_emac_mc_filter_bin_update(struct prueth_emac *emac, u8 hash, + u8 val) +{ + struct prueth *prueth = emac->prueth; + void __iomem *mc_filter_tbl; + u32 mc_filter_tbl_base; + void __iomem *ram; + + ram = prueth->mem[emac->dram].va; + mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl; + + mc_filter_tbl = ram + mc_filter_tbl_base; + writeb(val, mc_filter_tbl + hash); +} + +void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash) +{ + icssm_emac_mc_filter_bin_update + (emac, hash, + ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED); +} + +void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash) +{ + icssm_emac_mc_filter_bin_update + (emac, hash, + ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED); +} + +u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask) +{ + u8 hash; + int j; + + for (j = 0, hash = 0; j < ETH_ALEN; j++) + hash ^= (mac[j] & mask[j]); + + return hash; +} + +/** + * icssm_emac_ndo_set_rx_mode - EMAC set receive mode function + * @ndev: The EMAC network adapter + * + * Called when system wants to set the receive mode of the device. + * + */ +static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + bool promisc = ndev->flags & IFF_PROMISC; + struct netdev_hw_addr *ha; + struct prueth *prueth; + unsigned long flags; + void __iomem *sram; + u32 mask, reg; + u8 hash; + + prueth = emac->prueth; + sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va; + reg = readl(sram + EMAC_PROMISCUOUS_MODE_OFFSET); + + /* for LRE, it is a shared table. So lock the access */ + spin_lock_irqsave(&emac->addr_lock, flags); + + /* Disable and reset multicast filter, allows allmulti */ + icssm_emac_mc_filter_ctrl(emac, false); + icssm_emac_mc_filter_reset(emac); + icssm_emac_mc_filter_hashmask(emac, emac->mc_filter_mask); + + if (PRUETH_IS_EMAC(prueth)) { + switch (emac->port_id) { + case PRUETH_PORT_MII0: + mask = EMAC_P1_PROMISCUOUS_BIT; + break; + case PRUETH_PORT_MII1: + mask = EMAC_P2_PROMISCUOUS_BIT; + break; + default: + netdev_err(ndev, "%s: invalid port\n", __func__); + goto unlock; + } + + if (promisc) { + /* Enable promiscuous mode */ + reg |= mask; + } else { + /* Disable promiscuous mode */ + reg &= ~mask; + } + + writel(reg, sram + EMAC_PROMISCUOUS_MODE_OFFSET); + + if (promisc) + goto unlock; + } + + if (ndev->flags & IFF_ALLMULTI && !PRUETH_IS_SWITCH(prueth)) + goto unlock; + + icssm_emac_mc_filter_ctrl(emac, true); /* all multicast blocked */ + + if (netdev_mc_empty(ndev)) + goto unlock; + + netdev_for_each_mc_addr(ha, ndev) { + hash = icssm_emac_get_mc_hash(ha->addr, emac->mc_filter_mask); + icssm_emac_mc_filter_bin_allow(emac, hash); + } + +unlock: + spin_unlock_irqrestore(&emac->addr_lock, flags); +} + static int icssm_emac_hwtstamp_config_set(struct net_device *ndev, struct ifreq *ifr) { @@ -1497,13 +1693,115 @@ static int icssm_emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, return phy_do_ioctl(ndev, ifr, cmd); } +int icssm_emac_add_del_vid(struct prueth_emac *emac, + bool add, __be16 proto, u16 vid) +{ + struct prueth *prueth = emac->prueth; + u32 vlan_filter_tbl; + unsigned long flags; + void __iomem *ram; + u8 bit_index, val; + u16 byte_index; + + vlan_filter_tbl = prueth->fw_offsets->vlan_filter_tbl; + ram = prueth->mem[emac->dram].va; + + if (proto != htons(ETH_P_8021Q)) + return -EINVAL; + + if (vid >= ICSS_EMAC_FW_VLAN_FILTER_VID_MAX) + return -EINVAL; + + /* By default, VLAN ID 0 (priority tagged packets) is routed to + * host, so nothing to be done if vid = 0 + */ + if (!vid) + return 0; + + /* for LRE, it is a shared table. So lock the access */ + spin_lock_irqsave(&emac->addr_lock, flags); + + /* VLAN filter table is 512 bytes (4096 bit) bitmap. + * Each bit controls enabling or disabling corresponding + * VID. Therefore byte index that controls a given VID is + * can calculated as vid / 8 and the bit within that byte + * that controls VID is given by vid % 8. Allow untagged + * frames to host by default. + */ + byte_index = vid / BITS_PER_BYTE; + bit_index = vid % BITS_PER_BYTE; + val = readb(ram + vlan_filter_tbl + byte_index); + if (add) + val |= BIT(bit_index); + else + val &= ~BIT(bit_index); + writeb(val, ram + vlan_filter_tbl + byte_index); + + spin_unlock_irqrestore(&emac->addr_lock, flags); + + netdev_dbg(emac->ndev, "%s VID bit at index %d and bit %d\n", + add ? "Setting" : "Clearing", byte_index, bit_index); + + return 0; +} + +static int icssm_emac_ndo_vlan_rx_add_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct prueth_emac *emac = netdev_priv(dev); + + return icssm_emac_add_del_vid(emac, true, proto, vid); +} + +static int icssm_emac_ndo_vlan_rx_kill_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct prueth_emac *emac = netdev_priv(dev); + + return icssm_emac_add_del_vid(emac, false, proto, vid); +} + +static int icssm_emac_get_port_parent_id(struct net_device *dev, + struct netdev_phys_item_id *ppid) +{ + struct prueth_emac *emac = netdev_priv(dev); + struct prueth *prueth = emac->prueth; + + ppid->id_len = sizeof(prueth->base_mac); + memcpy(&ppid->id, &prueth->base_mac, ppid->id_len); + + return 0; +} + +static int icssm_emac_ndo_get_phys_port_name(struct net_device *ndev, + char *name, size_t len) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int err; + + err = snprintf(name, len, "p%d", emac->port_id); + + if (err >= len) + return -EINVAL; + + return 0; +} + static const struct net_device_ops emac_netdev_ops = { .ndo_open = icssm_emac_ndo_open, .ndo_stop = icssm_emac_ndo_stop, .ndo_start_xmit = icssm_emac_ndo_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = icssm_emac_ndo_tx_timeout, .ndo_get_stats64 = icssm_emac_ndo_get_stats64, + .ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode, .ndo_eth_ioctl = icssm_emac_ndo_ioctl, + .ndo_vlan_rx_add_vid = icssm_emac_ndo_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = icssm_emac_ndo_vlan_rx_kill_vid, + .ndo_setup_tc = icssm_emac_ndo_setup_tc, + .ndo_get_port_parent_id = icssm_emac_get_port_parent_id, + .ndo_get_phys_port_name = icssm_emac_ndo_get_phys_port_name, }; /* get emac_port corresponding to eth_node name */ @@ -1569,6 +1867,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, emac->prueth = prueth; emac->ndev = ndev; emac->port_id = port; + memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN); /* default mask */ /* by default eth_type is EMAC */ switch (port) { @@ -1610,7 +1909,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n"); } + spin_lock_init(&emac->lock); spin_lock_init(&emac->ptp_skb_lock); + spin_lock_init(&emac->addr_lock); /* get mac address from DT and set private and netdev addr */ ret = of_get_ethdev_address(eth_node, ndev); @@ -1639,6 +1940,10 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT); phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC; + + ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + ndev->netdev_ops = &emac_netdev_ops; ndev->ethtool_ops = &emac_ethtool_ops; @@ -1693,6 +1998,7 @@ static int icssm_prueth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, prueth); prueth->dev = dev; prueth->fw_data = device_get_match_data(dev); + prueth->fw_offsets = &fw_offsets_v2_1; eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); if (!eth_ports_node) @@ -1890,6 +2196,8 @@ static int icssm_prueth_probe(struct platform_device *pdev) prueth->emac[PRUETH_MAC1]->ndev; } + eth_random_addr(prueth->base_mac); + dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", (!eth0_node || !eth1_node) ? "single" : "dual"); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 1709b3b6c2be..8a5f1647466a 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -28,6 +28,9 @@ #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \ ICSSM_LRE_TAG_SIZE) +/* default timer for NSP and HSR/PRP */ +#define PRUETH_NSP_TIMER_MS (100) /* Refresh NSP counters every 100ms */ + #define PRUETH_REG_DUMP_VER 1 /* Encoding: 32-16: Reserved, 16-8: Reg dump version, 8-0: Ethertype */ @@ -293,6 +296,29 @@ enum prueth_mem { PRUETH_MEM_MAX, }; +/* Firmware offsets/size information */ +struct prueth_fw_offsets { + u32 index_array_offset; + u32 bin_array_offset; + u32 nt_array_offset; + u32 index_array_loc; + u32 bin_array_loc; + u32 nt_array_loc; + u32 index_array_max_entries; + u32 bin_array_max_entries; + u32 nt_array_max_entries; + u32 vlan_ctrl_byte; + u32 vlan_filter_tbl; + u32 mc_ctrl_byte; + u32 mc_filter_mask; + u32 mc_filter_tbl; + /* IEP wrap is used in the rx packet ordering logic and + * is different for ICSSM v1.0 vs 2.1 + */ + u32 iep_wrap; + u16 hash_mask; +}; + enum pruss_device { PRUSS_AM57XX = 0, PRUSS_AM43XX, @@ -314,6 +340,11 @@ struct prueth_private_data { bool support_switch; }; +struct nsp_counter { + unsigned long cookie; + u16 credit; +}; + /* data for each emac port */ struct prueth_emac { struct prueth *prueth; @@ -338,8 +369,16 @@ struct prueth_emac { const char *phy_id; u32 msg_enable; u8 mac_addr[6]; + unsigned char mc_filter_mask[ETH_ALEN]; /* for multicast filtering */ phy_interface_t phy_if; + spinlock_t lock; /* serialize access */ + spinlock_t addr_lock; /* serialize access to VLAN/MC filter table */ + + struct nsp_counter nsp_bc; + struct nsp_counter nsp_mc; + struct nsp_counter nsp_uc; + bool nsp_enabled; struct sk_buff *ptp_skb[PRUETH_PTP_TS_EVENTS]; spinlock_t ptp_skb_lock; /* serialize access */ @@ -367,19 +406,27 @@ struct prueth { unsigned int eth_type; size_t ocmc_ram_size; u8 emac_configured; + u8 base_mac[ETH_ALEN]; }; extern const struct ethtool_ops emac_ethtool_ops; +int icssm_emac_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data); void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, struct prueth_packet_info *pkt_info); int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, struct prueth_packet_info *pkt_info, const struct prueth_queue_info *rxqueue); - +int icssm_emac_add_del_vid(struct prueth_emac *emac, + bool add, __be16 proto, u16 vid); irqreturn_t icssm_prueth_ptp_tx_irq_handle(int irq, void *dev); irqreturn_t icssm_prueth_ptp_tx_irq_work(int irq, void *dev); +void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash); +void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash); +u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask); + void icssm_emac_set_stats(struct prueth_emac *emac, struct port_statistics *pstats); void icssm_emac_get_stats(struct prueth_emac *emac, diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c new file mode 100644 index 000000000000..8382bd8cab7c --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com + */ + +#include +#include +#include +#include +#include + +#include "../icssg/icssg_mii_rt.h" +#include "icssm_vlan_mcast_filter_mmap.h" +#include "icssm_prueth.h" + +static void icssm_emac_nsp_enable(void __iomem *counter, u16 credit) +{ + writel((credit << PRUETH_NSP_CREDIT_SHIFT) | PRUETH_NSP_ENABLE, + counter); +} + +/** + * icssm_prueth_enable_nsp - enable nsp + * + * @emac: EMAC data structure + * + */ +static void icssm_prueth_enable_nsp(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + void __iomem *dram; + + dram = prueth->mem[emac->dram].va; + + if (emac->nsp_bc.cookie) + icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_BC, + emac->nsp_bc.credit); + if (emac->nsp_mc.cookie) + icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_MC, + emac->nsp_mc.credit); + if (emac->nsp_uc.cookie) + icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_UC, + emac->nsp_uc.credit); +} + +static int icssm_emac_flower_parse_policer(struct prueth_emac *emac, + struct netlink_ext_ack *extack, + struct flow_cls_offload *cls, + u64 rate_bytes_per_sec) +{ + struct flow_rule *rule = flow_cls_offload_flow_rule(cls); + struct flow_dissector *dissector = rule->match.dissector; + u8 null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 mc_mac[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + struct flow_match_eth_addrs match; + struct nsp_counter *nsp = NULL; + char *str; + u32 pps; + + if (dissector->used_keys & + ~(BIT(FLOW_DISSECTOR_KEY_BASIC) | + BIT(FLOW_DISSECTOR_KEY_CONTROL) | + BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) { + NL_SET_ERR_MSG_MOD(extack, + "Unsupported keys used"); + return -EOPNOTSUPP; + } + + if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + NL_SET_ERR_MSG_MOD(extack, "Not matching on eth address"); + return -EOPNOTSUPP; + } + + flow_rule_match_eth_addrs(rule, &match); + + if (!ether_addr_equal_masked(match.key->src, null_mac, + match.mask->src)) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on source MAC not supported"); + return -EOPNOTSUPP; + } + + if (ether_addr_equal(match.key->dst, bc_mac)) { + if (!emac->nsp_bc.cookie || + emac->nsp_bc.cookie == cls->cookie) + nsp = &emac->nsp_bc; + else + NL_SET_ERR_MSG_MOD(extack, "BC Filter already set"); + str = "Broad"; + } else if (ether_addr_equal_masked(match.key->dst, mc_mac, mc_mac)) { + if (!emac->nsp_mc.cookie || + emac->nsp_mc.cookie == cls->cookie) + nsp = &emac->nsp_mc; + else + NL_SET_ERR_MSG_MOD(extack, "MC Filter already set"); + str = "Multi"; + } else { + if (!emac->nsp_uc.cookie || + emac->nsp_uc.cookie == cls->cookie) + nsp = &emac->nsp_uc; + else + NL_SET_ERR_MSG_MOD(extack, "UC Filter already set"); + str = "Uni"; + } + + if (!nsp) + return -EOPNOTSUPP; + + /* Calculate number of packets per second for given bps + * assuming min ethernet packet size + */ + pps = div_u64(rate_bytes_per_sec, ETH_ZLEN); + /* Convert that to packets per 100ms */ + pps /= MSEC_PER_SEC / PRUETH_NSP_TIMER_MS; + + nsp->cookie = cls->cookie; + nsp->credit = pps; + emac->nsp_enabled = emac->nsp_bc.cookie | emac->nsp_mc.cookie | + emac->nsp_uc.cookie; + + icssm_prueth_enable_nsp(emac); + + netdev_dbg(emac->ndev, + "%scast filter set to %d packets per %dms\n", str, + nsp->credit, PRUETH_NSP_TIMER_MS); + + return 0; +} + +static int icssm_emac_configure_clsflower(struct prueth_emac *emac, + struct flow_cls_offload *cls) +{ + struct flow_rule *rule = flow_cls_offload_flow_rule(cls); + struct netlink_ext_ack *extack = cls->common.extack; + const struct flow_action_entry *act; + int i; + + flow_action_for_each(i, act, &rule->action) { + switch (act->id) { + case FLOW_ACTION_POLICE: + return icssm_emac_flower_parse_policer + (emac, extack, cls, + act->police.rate_bytes_ps); + default: + NL_SET_ERR_MSG_MOD(extack, + "Action not supported"); + return -EOPNOTSUPP; + } + } + return -EOPNOTSUPP; +} + +static int icssm_emac_delete_clsflower(struct prueth_emac *emac, + struct flow_cls_offload *cls) +{ + struct prueth *prueth = emac->prueth; + void __iomem *dram; + + dram = prueth->mem[emac->dram].va; + + if (cls->cookie == emac->nsp_bc.cookie) { + emac->nsp_bc.cookie = 0; + emac->nsp_bc.credit = 0; + writel(0, dram + STORM_PREVENTION_OFFSET_BC); + } else if (cls->cookie == emac->nsp_mc.cookie) { + emac->nsp_mc.cookie = 0; + emac->nsp_mc.credit = 0; + writel(0, dram + STORM_PREVENTION_OFFSET_MC); + } else if (cls->cookie == emac->nsp_uc.cookie) { + emac->nsp_uc.cookie = 0; + emac->nsp_uc.credit = 0; + writel(0, dram + STORM_PREVENTION_OFFSET_UC); + } + + emac->nsp_enabled = emac->nsp_bc.cookie | emac->nsp_mc.cookie | + emac->nsp_uc.cookie; + + return 0; +} + +static int icssm_emac_setup_tc_cls_flower(struct prueth_emac *emac, + struct flow_cls_offload *cls_flower) +{ + switch (cls_flower->command) { + case FLOW_CLS_REPLACE: + return icssm_emac_configure_clsflower(emac, cls_flower); + case FLOW_CLS_DESTROY: + return icssm_emac_delete_clsflower(emac, cls_flower); + default: + return -EOPNOTSUPP; + } +} + +static int icssm_emac_setup_tc_block_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + struct prueth_emac *emac = cb_priv; + + if (!tc_cls_can_offload_and_chain0(emac->ndev, type_data)) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_CLSFLOWER: + return icssm_emac_setup_tc_cls_flower(emac, type_data); + default: + return -EOPNOTSUPP; + } +} + +static LIST_HEAD(emac_block_cb_list); + +int icssm_emac_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data) +{ + struct prueth_emac *emac = netdev_priv(dev); + + if (type == TC_SETUP_BLOCK) { + return flow_block_cb_setup_simple(type_data, + &emac_block_cb_list, + icssm_emac_setup_tc_block_cb, + emac, emac, true); + } + + return -EOPNOTSUPP; +} diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h index b13e0706ccec..0053191380b7 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_switch.h +++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h @@ -146,6 +146,11 @@ /* 4 bytes ? */ #define STP_INVALID_STATE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 33) +/* Shared RAM Offsets for Switch */ +/* NSP (Network Storm Prevention) timer re-uses NT timer */ +#define PRUETH_NSP_CREDIT_SHIFT 8 +#define PRUETH_NSP_ENABLE BIT(0) + /* DRAM Offsets for EMAC * Present on Both DRAM0 and DRAM1 */ diff --git a/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h new file mode 100644 index 000000000000..32b5c228c5fb --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com + * + * This file contains VLAN/Multicast filtering feature memory map + * + */ + +#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H +#define ICSS_VLAN_MULTICAST_FILTER_MM_H + +/* VLAN/Multicast filter defines & offsets, + * present on both PRU0 and PRU1 DRAM + */ + +/* Feature enable/disable values for multicast filtering */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED 0x00 +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED 0x01 + +/* Feature enable/disable values for VLAN filtering */ +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED 0x00 +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED 0x01 + +/* Add/remove multicast mac id for filtering bin */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED 0x01 +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED 0x00 + +/* Default HASH value for the multicast filtering Mask */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL 0xFF + +/* Size requirements for Multicast filtering feature */ +#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES 256 +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES 6 +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES 1 +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES 1 +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES 4 + +/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */ +#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES 512 +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES 1 +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES 4 + +/* Mask override set status */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET 1 +/* Mask override not set status */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET 0 +/* 6 bytes HASH Mask for the MAC */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET 0xF4 +/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET \ + (ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET + \ + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES) +/* Status indicating if the HASH override is done or not: 0: no, 1: yes */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS \ + (ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET + \ + ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES) +/* Multicast drop statistics */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET \ + (ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\ + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES) +/* Multicast table */ +#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE \ + (ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\ + ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES) + +/* Multicast filter defines & offsets for LRE + */ +#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT 0xE0 +/* one byte field : + * 0 -> multicast filtering disabled + * 1 -> multicast filtering enabled + */ +#define ICSS_LRE_FW_MULTICAST_FILTER_MASK 0xE4 +#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE 0x100 + +/* VLAN table Offsets */ +#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR 0x200 +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET 0xEF +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET \ + (ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET + \ + ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES) + +/* VLAN filter Control Bit maps */ +/* one bit field, bit 0: | 0 : VLAN filter disabled (default), + * 1: VLAN filter enabled + */ +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT 0 +/* one bit field, bit 1: | 0 : untagged host rcv allowed (default), + * 1: untagged host rcv not allowed + */ +#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT 1 +/* one bit field, bit 1: | 0 : priotag host rcv allowed (default), + * 1: priotag host rcv not allowed + */ +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT 2 +/* one bit field, bit 1: | 0 : skip sv vlan flow + * :1 : take sv vlan flow (not applicable for dual emac ) + */ +#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT 3 + +/* VLAN IDs */ +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID 0 +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN 0x0000 +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX 0x0FFF + +/* VLAN Filtering Commands */ +#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD 0x00 +#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD 0x01 + +/* Switch defines for VLAN/MC filtering */ +/* SRAM + * VLAN filter defines & offsets + */ +#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE 0x1FE +/* one bit field | 0 : VLAN filter disabled + * | 1 : VLAN filter enabled + */ +#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR 0x200 + +#endif /* ICSS_MULTICAST_FILTER_MM_H */ From patchwork Fri Feb 14 08:53:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974623 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CD039C02198 for ; Fri, 14 Feb 2025 08:57:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=xUJfqIO3kUYbuf/ww2029FZ6c5/2rI4Ixt7Gq+yPZvY=; b=SFLoytysIb8lo3udF5Km/X60EB UokB7GxwYcxfmWSgugytj86yr0EU9NeASRsBRz6lHVK+oLZl46MSoRyh58ZMcz51G/g9/qP1Uc0W4 Vt4Vye8QjxJLRVksEAkJ99gyXwnkP+EupETs5Qlco3KH5lZ73iuDl1f2VxWVb+XCQw+DaBwA7vbbO 7uFh9XGk/5ukCwdla1y2KkWaWk+cWGzJK/A89+d5A9fHIG0euf+LGng+4Al+OJdT7SOiTefIPx4+5 CelglfrDCtQVZFfio7AQfWjgoYqse14ijNmyxuOJvteilwKn4Kruv6oeRB7hoU138BscnAVg/9OoR 7NCzZXkA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tirVH-0000000ECht-0SX7; Fri, 14 Feb 2025 08:56:55 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tirSR-0000000EC4G-3ICp for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 08:54:01 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=xUJfqIO3kUYbuf/ww2029FZ6c5/2rI4Ixt7Gq+yPZvY=; b=TwPzC2K16otFhKhCpjPj5oYW5p 3829VnzJPr+tG6o/TDx8hJxEn5KlcffsM83gwXupQDs5rtVJqblnYNzXRV8gdidTipVslf1rp07wy kAJLqnwsxpu3HdZ51q0v2MCWz19BopxtWM9Ld+i0mnH1e/ttZId1BnY3/DiPXCVr1mC53RInT6ra4 kXyrwPIsLQcITVVJqCVt/ynK0HzC2LSs5bFVM5uIoctKxc/IZgqtNg8N1RCmGFYhyYeVBRXOzCfIC 8JpUY+FVWswtUlzS6wQbyUCZoLMaN5jRaAcBt5LK6EK2ygkfEnI9wo97RB/KJELfsO+GYjO0EcbVu Lq6CkgVg==; Received: from [122.175.9.182] (port=45524 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tirSM-00050J-1Y; Fri, 14 Feb 2025 14:23:54 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 08/10] net: ti: prueth: Adds support for RX interrupt coalescing/pacing Date: Fri, 14 Feb 2025 14:23:13 +0530 Message-Id: <20250214085315.1077108-9-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250214_005359_885575_005E09D3 X-CRM114-Status: GOOD ( 32.13 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Murali Karicheri Changes for supporting RX interrupt pacing feature using eCAP peripheral available in PRU-ICSS. Instead of interrupting the CPU for every packet received, the firmware running on the PRU-ICSS will interrupt the CPU based on the configured time period, if interrupt pacing is enabled. The time period can be configured using ethtool. RX pacing/coalescing is implemented Using eCAP timer events to give CPU breathing space from ISR to perform other critical tasks. The changes include new eCAP driver module which will initialization and configures the ICSS eCAP HW. Makefile and Kernel config has been updated to compile the eCAP driver and to insert the module. Signed-off-by: Murali Karicheri Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/Kconfig | 12 + drivers/net/ethernet/ti/Makefile | 2 + drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 38 +++ drivers/net/ethernet/ti/icssm/icssm_prueth.c | 25 +- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 3 + .../net/ethernet/ti/icssm/icssm_prueth_ecap.c | 312 ++++++++++++++++++ .../net/ethernet/ti/icssm/icssm_prueth_ecap.h | 47 +++ drivers/net/ethernet/ti/icssm/icssm_switch.h | 23 ++ 8 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.c create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.h diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 96ad084f1dce..b0fc6d348151 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -227,6 +227,18 @@ config TI_ICSS_IEP To compile this driver as a module, choose M here. The module will be called icss_iep. +config TI_PRUETH_ECAP + tristate "TI PRUETH ECAP driver" + depends on TI_PRUSS + default TI_PRUSS + help + This enables support for the PRU-ICSS Enhanced Capture (eCAP) driver + used for rx interrupt pacing support in PRU Driver/firmwares + (Dual EMAC, HSR, PRP). + + To compile this driver as a module, choose M here. The module + will be called prueth_ecap. + config TI_PRUETH tristate "TI PRU Ethernet EMAC driver" depends on PRU_REMOTEPROC diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 852640ce2b15..dce14a30d4ac 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -49,3 +49,5 @@ icssg-y := icssg/icssg_common.o \ icssg/icssg_ethtool.o obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o + +obj-$(CONFIG_TI_PRUETH_ECAP) += icssm/icssm_prueth_ecap.o diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c index e4b2a0b7d275..31d6908dd1b1 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -8,6 +8,7 @@ #include #include #include "icssm_prueth.h" +#include "icssm_prueth_ecap.h" #include "icssm_vlan_mcast_filter_mmap.h" #include "../icssg/icss_iep.h" @@ -301,6 +302,40 @@ static int icssm_emac_get_ts_info(struct net_device *ndev, return 0; } +static int icssm_emac_get_coalesce(struct net_device *ndev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + struct prueth_ecap *ecap; + + ecap = prueth->ecap; + if (IS_ERR(ecap)) + return -EOPNOTSUPP; + + return ecap->get_coalesce(emac, &coal->use_adaptive_rx_coalesce, + &coal->rx_coalesce_usecs); +} + +static int icssm_emac_set_coalesce(struct net_device *ndev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + struct prueth_ecap *ecap; + + ecap = prueth->ecap; + if (IS_ERR(ecap)) + return -EOPNOTSUPP; + + return ecap->set_coalesce(emac, coal->use_adaptive_rx_coalesce, + coal->rx_coalesce_usecs); +} + /* Ethtool support for EMAC adapter */ const struct ethtool_ops emac_ethtool_ops = { .get_drvinfo = icssm_emac_get_drvinfo, @@ -315,5 +350,8 @@ const struct ethtool_ops emac_ethtool_ops = { .get_rmon_stats = icssm_emac_get_rmon_stats, .get_eth_mac_stats = icssm_emac_get_eth_mac_stats, .get_ts_info = icssm_emac_get_ts_info, + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, + .get_coalesce = icssm_emac_get_coalesce, + .set_coalesce = icssm_emac_set_coalesce, }; EXPORT_SYMBOL_GPL(emac_ethtool_ops); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index e8f8fe5795b3..5011dde6859f 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -30,6 +30,7 @@ #include "icssm_prueth.h" #include "icssm_vlan_mcast_filter_mmap.h" +#include "icssm_prueth_ecap.h" #include "../icssg/icssg_mii_rt.h" #include "../icssg/icss_iep.h" @@ -1209,8 +1210,10 @@ static int icssm_emac_ndo_open(struct net_device *ndev) { struct prueth_emac *emac = netdev_priv(ndev); struct prueth *prueth = emac->prueth; + struct prueth_ecap *ecap; int ret; + ecap = prueth->ecap; /* set h/w MAC as user might have re-configured */ ether_addr_copy(emac->mac_addr, ndev->dev_addr); @@ -1220,6 +1223,9 @@ static int icssm_emac_ndo_open(struct net_device *ndev) icssm_prueth_emac_config(emac); icssm_emac_set_stats(emac, &emac->stats); + /* initialize ecap for interrupt pacing */ + if (!IS_ERR(ecap)) + ecap->init(emac); if (!prueth->emac_configured) { icssm_iptp_dram_init(emac); @@ -2173,12 +2179,25 @@ static int icssm_prueth_probe(struct platform_device *pdev) goto netdev_exit; } + /* Make rx interrupt pacing optional so that users can use ECAP for + * other use cases if needed + */ + prueth->ecap = icssm_prueth_ecap_get(np); + if (IS_ERR(prueth->ecap)) { + ret = PTR_ERR(prueth->ecap); + if (ret != -EPROBE_DEFER) + dev_info(dev, + "No ECAP. Rx interrupt pacing disabled\n"); + else + goto iep_put; + } + /* register the network devices */ if (eth0_node) { ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); if (ret) { dev_err(dev, "can't register netdev for port MII0"); - goto iep_put; + goto ecap_put; } prueth->registered_netdevs[PRUETH_MAC0] = @@ -2214,6 +2233,10 @@ static int icssm_prueth_probe(struct platform_device *pdev) unregister_netdev(prueth->registered_netdevs[i]); } +ecap_put: + if (!IS_ERR(prueth->ecap)) + icssm_prueth_ecap_put(prueth->ecap); + iep_put: icss_iep_put(prueth->iep); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 8a5f1647466a..dc6284441f6d 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "icssm_switch.h" #include "icssm_prueth_ptp.h" @@ -396,6 +397,7 @@ struct prueth { struct regmap *mii_rt; struct icss_iep *iep; + struct prueth_ecap *ecap; const struct prueth_private_data *fw_data; struct prueth_fw_offsets *fw_offsets; @@ -405,6 +407,7 @@ struct prueth { unsigned int eth_type; size_t ocmc_ram_size; + struct mutex mlock; /* serialize access */ u8 emac_configured; u8 base_mac[ETH_ALEN]; }; diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.c new file mode 100644 index 000000000000..7603188103c3 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* PRUETH Ecap driver for Interrupt pacing support. eCAP is used by + * firmware to implement Rx Interrupt pacing for PRUETH driver using + * ECAP1 and ECAP2. Firmware uses ECAP as a timer to implement + * interrupt pacing logic. For HSR/PRP, the interrupt pacing can + * be enabled/disabled for both ports together as there is a common + * control for both ports, where as for Dual EMAC, interrupt pacing + * can be enabled or disabled independently for both Ethernet ports. + * SRAM memory location stores the configuration for interrupt pacing + * such as enable/disable flag and timeout values. + * + * TODO: This is marked as a HACK driver since the correct solution + * is to move the initialization of the ECAP registers to firmware. + * Driver has nothing to do ECAP as it is used by firmware and it + * is expected that firmware does the initialization. + * + * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com + * Murali Karicheri + */ + +#include +#include +#include +#include +#include +#include + +#include "icssm_switch.h" +#include "icssm_prueth_ecap.h" + +/* ECAP registers */ +#define ECAP_CAP1 8 +#define ECAP_CAP2 0xC +#define ECAP_ECCTL2 0x2A + +#define ECAP_ECCTL2_TSCTRSTOP_MASK BIT(4) +#define ECAP_ECCTL2_CAP_APWM_MASK BIT(9) + +#define ECAP_ECCTL2_INIT_VAL (ECAP_ECCTL2_TSCTRSTOP_MASK | \ + ECAP_ECCTL2_CAP_APWM_MASK) +#define ECAP_CAP2_MAX_COUNT 0xFFFFFFFF + +/* TODO: Driver assumes that ECAP runs at 200Mhz clock. But on some + * platforms, PRU ICSS clock rate may be changed by user in which case + * the pacing logic will not work as expected. Update the driver and + * firmware if ECAP/PRUSS clock rate is ever changed. Based on this + * assumption each tick is 5 nsec. i.e 1000/200 + */ +#define ECAP_TICK_NSEC 5 + +/* in usec */ +/* Duration of 3 frames of 1528 bytes each. If we go beyond this, + * receive buffer overflow may happen assuming 4 MTU buffer. So + * set this as the limit + */ +#define MAX_RX_TIMEOUT_USEC (123 * 3) + +/* Dual EMAC defaults */ +static struct rx_int_pacing_offsets pacing_offsets_defaults[PRUETH_NUM_MACS] = { + { INTR_PAC_STATUS_OFFSET_PRU0, INTR_PAC_TMR_EXP_OFFSET_PRU0, + INTR_PAC_PREV_TS_OFFSET_PRU0 }, + { INTR_PAC_STATUS_OFFSET_PRU1, INTR_PAC_TMR_EXP_OFFSET_PRU1, + INTR_PAC_PREV_TS_OFFSET_PRU1 }, +}; + +static int icssm_prueth_ecap_config_pacing(struct prueth_emac *emac, + u32 use_adaptive, + u32 new_timeout_val) +{ + struct rx_int_pacing_offsets *offsets; + struct prueth *prueth = emac->prueth; + u8 val = INTR_PAC_DIS_ADP_LGC_DIS; + struct prueth_ecap *ecap; + void __iomem *sram; + u32 pacing_ctrl; + int port; + + ecap = prueth->ecap; + sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va; + port = (emac->port_id == PRUETH_PORT_MII0) ? + PRUETH_MAC0 : PRUETH_MAC1; + offsets = &ecap->int_pacing_offsets[port]; + pacing_ctrl = offsets->rx_int_pacing_ctrl; + + if (!new_timeout_val) { + /* disable pacing */ + writeb_relaxed(val, sram + pacing_ctrl); + /* Timeout separate */ + ecap->timeout[port] = new_timeout_val; + return 0; + } + + if (use_adaptive) + val = INTR_PAC_ENA_ADP_LGC_ENA; + else + val = INTR_PAC_ENA_ADP_LGC_DIS; + + if (!ecap->timeout[port]) { + /* disable to enable transition */ + writeb_relaxed(INTR_PAC_DIS_ADP_LGC_DIS, sram + pacing_ctrl); + /* For EMAC set timeout for specific port and for + * LRE for both ports + */ + if (PRUETH_IS_EMAC(prueth)) { + if (!port) { + offsets = + &ecap->int_pacing_offsets[PRUETH_MAC0]; + writel_relaxed(new_timeout_val * + NSEC_PER_USEC / ECAP_TICK_NSEC, + sram + + offsets->rx_int_pacing_exp); + writel_relaxed(INTR_PAC_PREV_TS_RESET_VAL, + sram + + offsets->rx_int_pacing_prev); + ecap->timeout[PRUETH_MAC0] = new_timeout_val; + } else { + offsets = + &ecap->int_pacing_offsets[PRUETH_MAC1]; + writel_relaxed(new_timeout_val * + NSEC_PER_USEC / ECAP_TICK_NSEC, + sram + + offsets->rx_int_pacing_exp); + writel_relaxed(INTR_PAC_PREV_TS_RESET_VAL, + sram + + offsets->rx_int_pacing_prev); + ecap->timeout[PRUETH_MAC1] = new_timeout_val; + } + } + } else { + /* update */ + if (PRUETH_IS_EMAC(prueth)) { + if (!port) { + offsets = + &ecap->int_pacing_offsets[PRUETH_MAC0]; + writel_relaxed(new_timeout_val * + NSEC_PER_USEC / ECAP_TICK_NSEC, + sram + + offsets->rx_int_pacing_exp); + ecap->timeout[PRUETH_MAC0] = new_timeout_val; + } else { + offsets = + &ecap->int_pacing_offsets[PRUETH_MAC1]; + writel_relaxed(new_timeout_val * + NSEC_PER_USEC / ECAP_TICK_NSEC, + sram + + offsets->rx_int_pacing_exp); + ecap->timeout[PRUETH_MAC1] = new_timeout_val; + } + } + } + + writeb_relaxed(val, sram + pacing_ctrl); + + return 0; +} + +/** + * icssm_prueth_ecap_init - ecap driver init + * + * @emac: EMAC data structure + * + */ +static void icssm_prueth_ecap_init(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + + if (!prueth->emac_configured || PRUETH_IS_EMAC(prueth)) + icssm_prueth_ecap_config_pacing(emac, 0, 0); +} + +static int icssm_prueth_ecap_get_coalesce(struct prueth_emac *emac, + u32 *use_adaptive_rx_coalesce, + u32 *rx_coalesce_usecs) +{ + struct rx_int_pacing_offsets *pacing_offsets; + struct prueth *prueth = emac->prueth; + struct prueth_ecap *ecap; + void __iomem *sram; + int port; + u32 val; + + ecap = prueth->ecap; + sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va; + port = (emac->port_id == PRUETH_PORT_MII0) ? + PRUETH_MAC0 : PRUETH_MAC1; + pacing_offsets = &ecap->int_pacing_offsets[port]; + val = readb_relaxed(sram + pacing_offsets->rx_int_pacing_ctrl); + *use_adaptive_rx_coalesce = (val == INTR_PAC_ENA_ADP_LGC_ENA); + *rx_coalesce_usecs = ecap->timeout[port]; + + return 0; +} + +static int icssm_prueth_ecap_set_coalesce(struct prueth_emac *emac, + u32 use_adaptive_rx_coalesce, + u32 rx_coalesce_usecs) +{ + struct prueth *prueth = emac->prueth; + int ret; + + if (rx_coalesce_usecs > MAX_RX_TIMEOUT_USEC) + return -EINVAL; + + mutex_lock(&prueth->mlock); + /* Start or restart the pacing timer. */ + ret = icssm_prueth_ecap_config_pacing(emac, use_adaptive_rx_coalesce, + rx_coalesce_usecs); + mutex_unlock(&prueth->mlock); + + return ret; +} + +void icssm_prueth_ecap_put(struct prueth_ecap *ecap) +{ + device_lock(ecap->dev); + ecap->client_np = NULL; + device_unlock(ecap->dev); + put_device(ecap->dev); +} +EXPORT_SYMBOL_GPL(icssm_prueth_ecap_put); + +struct prueth_ecap *icssm_prueth_ecap_get(struct device_node *np) +{ + struct platform_device *pdev; + struct device_node *ecap_np; + struct prueth_ecap *ecap; + + ecap_np = of_parse_phandle(np, "ti,ecap", 0); + if (!ecap_np || !of_device_is_available(ecap_np)) + return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(ecap_np); + of_node_put(ecap_np); + + if (!pdev) + /* probably IEP not yet probed */ + return ERR_PTR(-EPROBE_DEFER); + + ecap = platform_get_drvdata(pdev); + if (!ecap) + return ERR_PTR(-EPROBE_DEFER); + + device_lock(ecap->dev); + if (ecap->client_np) { + device_unlock(ecap->dev); + dev_err(ecap->dev, "ECAP is already acquired by %s", + ecap->client_np->name); + return ERR_PTR(-EBUSY); + } + ecap->client_np = np; + device_unlock(ecap->dev); + get_device(ecap->dev); + + return ecap; +} +EXPORT_SYMBOL_GPL(icssm_prueth_ecap_get); + +static int icssm_prueth_ecap_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct prueth_ecap *ecap; + struct resource *res; + int i; + + ecap = devm_kzalloc(dev, sizeof(*ecap), GFP_KERNEL); + if (!ecap) + return -ENOMEM; + + ecap->dev = dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ecap->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ecap->base)) + return -ENODEV; + + /* Initialize the ECAP timer. It is a common timer used + * by firmware for rx interrupt pacing. + */ + writew_relaxed(ECAP_ECCTL2_INIT_VAL, ecap->base + ECAP_ECCTL2); + writel_relaxed(ECAP_CAP2_MAX_COUNT, ecap->base + ECAP_CAP1); + writel_relaxed(ECAP_CAP2_MAX_COUNT, ecap->base + ECAP_CAP2); + + /* initialize SRAM memory offsets for rx pace time control */ + for (i = 0; i < PRUETH_NUM_MACS; i++) + ecap->int_pacing_offsets[i] = pacing_offsets_defaults[i]; + ecap->get_coalesce = icssm_prueth_ecap_get_coalesce; + ecap->set_coalesce = icssm_prueth_ecap_set_coalesce; + ecap->init = icssm_prueth_ecap_init; + + dev_set_drvdata(dev, ecap); + + return 0; +} + +static const struct of_device_id prueth_ecap_of_match[] = { + { .compatible = "ti,pruss-ecap", }, + { } +}; +MODULE_DEVICE_TABLE(of, prueth_ecap_of_match); + +static struct platform_driver prueth_ecap_driver = { + .driver = { + .name = "prueth-ecap", + .of_match_table = prueth_ecap_of_match, + }, + .probe = icssm_prueth_ecap_probe, +}; +module_platform_driver(prueth_ecap_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TI PRUETH ECAP driver for Rx Interrupt pacing"); +MODULE_AUTHOR("Murali Karicheri "); diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.h new file mode 100644 index 000000000000..d422756bc27f --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_ecap.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Texas Instruments ICSS Enhanced Capture (eCAP) Driver + * + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * + */ +#ifndef __NET_TI_PRUETH_ECAP_H +#define __NET_TI_PRUETH_ECAP_H + +#include "icssm_prueth.h" + +/* SRAM offsets for firmware pacing timer configuration */ +struct rx_int_pacing_offsets { + u32 rx_int_pacing_ctrl; + u32 rx_int_pacing_exp; + u32 rx_int_pacing_prev; +}; + +struct prueth_ecap { + struct device *dev; + void __iomem *base; + struct device_node *client_np; + struct rx_int_pacing_offsets int_pacing_offsets[PRUETH_NUM_MACS]; + u32 timeout[PRUETH_NUM_MACS]; + void (*init)(struct prueth_emac *emac); + int (*get_coalesce)(struct prueth_emac *emac, + u32 *use_adaptive_rx_coalesce, + u32 *rx_coalesce_usecs); + int (*set_coalesce)(struct prueth_emac *emac, + u32 use_adaptive_rx_coalesce, + u32 rx_coalesce_usecs); +}; + +#if IS_ENABLED(CONFIG_TI_PRUETH_ECAP) +struct prueth_ecap *icssm_prueth_ecap_get(struct device_node *np); +void icssm_prueth_ecap_put(struct prueth_ecap *ecap); +#else +static inline struct prueth_ecap *icssm_prueth_ecap_get(struct device_node *np) +{ + return ERR_PTR(-ENODEV); +} + +static inline void icssm_prueth_ecap_put(struct prueth_ecap *ecap) +{}; +#endif + +#endif /* __NET_TI_PRUETH_ECAP_H */ diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h index 0053191380b7..cb5ddd536747 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_switch.h +++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h @@ -259,4 +259,27 @@ #define P0_COL_BUFFER_OFFSET 0xEE00 #define P0_Q1_BUFFER_OFFSET 0x0000 +/* Below Rx Interrupt pacing defines. */ +/* shared RAM */ +/* 1 byte for pace control */ +#define INTR_PAC_STATUS_OFFSET 0x1FAF +#define INTR_PAC_STATUS_OFFSET_PRU1 0x1FAE +#define INTR_PAC_STATUS_OFFSET_PRU0 0x1FAF +/* Interrupt Pacing disabled, Adaptive logic disabled */ +#define INTR_PAC_DIS_ADP_LGC_DIS 0x0 +/* Interrupt Pacing enabled, Adaptive logic disabled */ +#define INTR_PAC_ENA_ADP_LGC_DIS 0x1 +/* Interrupt Pacing enabled, Adaptive logic enabled */ +#define INTR_PAC_ENA_ADP_LGC_ENA 0x2 + +/* 4 bytes | previous TS from eCAP TSCNT for PRU 0 */ +#define INTR_PAC_PREV_TS_OFFSET_PRU0 0x1FB0 +/* 4 bytes | timer expiration value for PRU 0 */ +#define INTR_PAC_TMR_EXP_OFFSET_PRU0 0x1FB4 +/* 4 bytes | previous TS from eCAP TSCNT for PRU 1 */ +#define INTR_PAC_PREV_TS_OFFSET_PRU1 0x1FB8 +/* 4 bytes | timer expiration value for PRU 1 */ +#define INTR_PAC_TMR_EXP_OFFSET_PRU1 0x1FBC +#define INTR_PAC_PREV_TS_RESET_VAL 0x0 + #endif /* __ICSS_SWITCH_H */ From patchwork Fri Feb 14 08:53:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974624 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 07717C02198 for ; Fri, 14 Feb 2025 08:58:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=GFtBsDbwRsR/crt8cPI3NZAjnEiA9mCcWyHWPic5WA8=; b=X9BbGz4GDWuLHfj3WzWd4Af5V9 tKHnF2NkQUM2soXwwMqnh5tYCrdEfXjFYG8NfHGE8Yj0o8O6K8jeAQMhfjXUGrWmxsMQSiqb/cCDF SGS/P2hEIZ+PqGsNkSU/NtoXyz0wuXm/h6jKy184qGOKtE0Ytgkp9FB5CtVSn2kNS7C844Ahd0RXe 2Ppq4CAYVFLmw3B/MiQREyO/dz78U/4mzffyuV+HmBPSGLOZT+dLsZCFb3yl2Q8EOHnCm1YXOLPtj T1/Uqawc/1sLj4YKrqX9PRVP8zfY3ZiH3UYlGD8D7I+IeVljOweebADoXCODTVsZZAwsrEvFzvNbI VLvn2bWQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tirWf-0000000ED3M-3X8c; Fri, 14 Feb 2025 08:58:21 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tirSh-0000000EC7r-2wSR for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 08:54:16 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=GFtBsDbwRsR/crt8cPI3NZAjnEiA9mCcWyHWPic5WA8=; b=b6vWO3SLLNU0mBJ2vYMXCIdTrZ CrJbjdlYfmP7QMPsgatNewRq35a9FHOM7zINju+WUE81lQNIR1r+JOF2L4Q6pWT8qb839pyvw5Uye LVVjCElVzI+WfEwjr+gJJum6L3GXAlno64hR1uWyVhCjqdYqyXj3Jb3Oh7qp6GoSqfxyGn1giyyoM Ks1yVjkb0j1TOlR879br4z4YBObK995tj5QTELeL/SmFthbTcR3qrlXL4BT+h+tE/lk8vcTCgoQYA VHgoKkqj6v8BT29IvKpcC5+z4BLpByfYVOYX3M2NLEDOCN84j6gopsizolNq+M8OS7Pts2LYZQPis nhmHbJ9Q==; Received: from [122.175.9.182] (port=45524 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tirSd-00050J-2H; Fri, 14 Feb 2025 14:24:11 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 09/10] net: ti: prueth: Adds power management support for PRU-ICSS Date: Fri, 14 Feb 2025 14:23:14 +0530 Message-Id: <20250214085315.1077108-10-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250214_005415_764721_C444B268 X-CRM114-Status: GOOD ( 12.04 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Changes for supporting the sleep/resume feature for PRU-ICSS. PRU-ICSS will be kept in IDLE mode for optimal power consumption by Linux power management subsystem and will be resumed when it is required. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Basharath Hussain Khaja Signed-off-by: Parvathi Pudi --- drivers/net/ethernet/ti/icssm/icssm_prueth.c | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index 5011dde6859f..dfceb8fddd33 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -2321,6 +2321,67 @@ static void icssm_prueth_remove(struct platform_device *pdev) pru_rproc_put(prueth->pru0); } +#ifdef CONFIG_PM_SLEEP +static int icssm_prueth_suspend(struct device *dev) +{ + struct prueth *prueth = dev_get_drvdata(dev); + struct net_device *ndev; + int i, ret; + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + ndev = prueth->registered_netdevs[i]; + + if (!ndev) + continue; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ret = icssm_emac_ndo_stop(ndev); + if (ret < 0) { + netdev_err(ndev, "failed to stop: %d", ret); + return ret; + } + } + } + + pruss_cfg_ocp_master_ports(prueth->pruss, 0); + + return 0; +} + +static int icssm_prueth_resume(struct device *dev) +{ + struct prueth *prueth = dev_get_drvdata(dev); + struct net_device *ndev; + int i, ret; + + pruss_cfg_ocp_master_ports(prueth->pruss, 1); + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + ndev = prueth->registered_netdevs[i]; + + if (!ndev) + continue; + + if (netif_running(ndev)) { + ret = icssm_emac_ndo_open(ndev); + if (ret < 0) { + netdev_err(ndev, "failed to start: %d", ret); + return ret; + } + netif_device_attach(ndev); + } + } + + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops prueth_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume) +}; + /* AM57xx SoC-specific firmware data */ static struct prueth_private_data am57xx_prueth_pdata = { .driver_data = PRUSS_AM57XX, @@ -2346,6 +2407,7 @@ static struct platform_driver prueth_driver = { .driver = { .name = "prueth", .of_match_table = prueth_dt_match, + .pm = &prueth_dev_pm_ops, }, }; module_platform_driver(prueth_driver); From patchwork Fri Feb 14 08:53:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parvathi Pudi X-Patchwork-Id: 13974625 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 72CD4C02198 for ; Fri, 14 Feb 2025 09:00:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=TxlRvYVV9khSZoxHTmi6Xm+xr2AQ+F0Z9nuDl3ZM9+Y=; b=fUA8ummOJZ1bZBKEc1i7BczZmG 0mQrLmSKlfk3SuHRhUbgxK1MmsTsG3BghDBeDlftmZ56NX2o/vKkAc6XYiy33aJHY7YdDMaJ+Y1On 57QZ5O8us5aj4Rcm4CivsGNEz/LhIYuaplklspiixOTpAGsnlpN7cpOzOSw8oE8TaMLc5RUn9f7LS rioDz05WTjaT2rvKskowT1AT+obPJwP8eZmn8xRM655X+LOOJCg2ZWdBKaTbXpAh7dJrcCXc9qdNF fPsmQS8zQVgccDXktr/AbZVhMqVk8H7FlmwS2CyepdoVBqVacBfxCfuAjkBehml2rLXuZKwDZJG7A CFq2bixw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tirY5-0000000EDFn-20G8; Fri, 14 Feb 2025 08:59:49 +0000 Received: from server.wki.vra.mybluehostin.me ([162.240.238.73]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tirSz-0000000ECC3-0LhQ for linux-arm-kernel@lists.infradead.org; Fri, 14 Feb 2025 08:54:34 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=couthit.com ; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=TxlRvYVV9khSZoxHTmi6Xm+xr2AQ+F0Z9nuDl3ZM9+Y=; b=IAgOutDXlTV7f8paqVi7ze48Uf QaqjVPTOg+IsBteCrfmS7OXmowYm8gbJEndF8REIZ1kMQ8JWhaxJ5j6YvlYRHQUC8sC6qsL/GTRDN VzDswVN+GAHvJC10L37032/IGF14NXlf10HCqBU44WPZC6vRmTL30205soeSfRZ+l00muCx3PoXbc xysV/NXfghDWiYDjsLU2Iv3cu5/p1UDVzkD2HUkTATgX4184L8ouJ+H5VogMg0PKg2XSenZ4taXfk z6NEG1CfwTTibQ3ptd6LqJ43zI+E0mTwkstVhTJM3XaTXW3DqXWVfHgltwFmHwJBSvD8sARewkcVR rBnMuqjw==; Received: from [122.175.9.182] (port=45524 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tirSv-00050J-0x; Fri, 14 Feb 2025 14:24:29 +0530 From: parvathi To: danishanwar@ti.com, rogerq@kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, nm@ti.com, ssantosh@kernel.org, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, diogo.ivo@siemens.com, m-karicheri2@ti.com, horms@kernel.org, jacob.e.keller@intel.com, m-malladi@ti.com, javier.carrasco.cruz@gmail.com, afd@ti.com, s-anna@ti.com Cc: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, pratheesh@ti.com, prajith@ti.com, vigneshr@ti.com, praneeth@ti.com, srk@ti.com, rogerq@ti.com, krishna@couthit.com, pmohan@couthit.com, mohan@couthit.com Subject: [PATCH net-next v3 10/10] soc: ti: PRUSS OCP configuration Date: Fri, 14 Feb 2025 14:23:15 +0530 Message-Id: <20250214085315.1077108-11-parvathi@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250214054702.1073139-1-parvathi@couthit.com> References: <20250214054702.1073139-1-parvathi@couthit.com> MIME-Version: 1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.wki.vra.mybluehostin.me X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - couthit.com X-Get-Message-Sender-Via: server.wki.vra.mybluehostin.me: authenticated_id: parvathi@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: parvathi@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250214_005433_148836_AABB6A95 X-CRM114-Status: GOOD ( 18.57 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roger Quadros Updates OCP master port configuration to enable memory access outside of the PRU-ICSS subsystem. This set of changes configures PRUSS_SYSCFG.STANDBY_INIT bit either to enable or disable the OCP master ports (applicable only on SoCs using OCP interconnect like the OMAP family). Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/soc/ti/pruss.c | 77 +++++++++++++++++++++++++++++++++++- include/linux/pruss_driver.h | 6 +++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index d7634bf5413a..a0e233da052c 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -25,14 +25,19 @@ #include #include "pruss.h" +#define SYSCFG_STANDBY_INIT BIT(4) +#define SYSCFG_SUB_MWAIT_READY BIT(5) + /** * struct pruss_private_data - PRUSS driver private data * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock + * @has_ocp_syscfg: flag to indicate if OCP SYSCFG is present */ struct pruss_private_data { bool has_no_sharedram; bool has_core_mux_clock; + bool has_ocp_syscfg; }; /** @@ -286,6 +291,72 @@ int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, } EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable); +/** + * pruss_cfg_ocp_master_ports() - configure PRUSS OCP master ports + * @pruss: the pruss instance handle + * @enable: set to true for enabling or false for disabling the OCP master ports + * + * This function programs the PRUSS_SYSCFG.STANDBY_INIT bit either to enable or + * disable the OCP master ports (applicable only on SoCs using OCP interconnect + * like the OMAP family). Clearing the bit achieves dual functionalities - one + * is to deassert the MStandby signal to the device PRCM, and the other is to + * enable OCP master ports to allow accesses outside of the PRU-ICSS. The + * function has to wait for the PRCM to acknowledge through the monitoring of + * the PRUSS_SYSCFG.SUB_MWAIT bit when enabling master ports. Setting the bit + * disables the master access, and also signals the PRCM that the PRUSS is ready + * for Standby. + * + * Return: 0 on success, or an error code otherwise. ETIMEDOUT is returned + * when the ready-state fails. + */ +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable) +{ + const struct pruss_private_data *data; + u32 syscfg_val, i; + int ret; + + if (IS_ERR_OR_NULL(pruss)) + return -EINVAL; + + data = of_device_get_match_data(pruss->dev); + + /* nothing to do on non OMAP-SoCs */ + if (!data || !data->has_ocp_syscfg) + return 0; + + /* assert the MStandby signal during disable path */ + if (!enable) + return pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, + SYSCFG_STANDBY_INIT, + SYSCFG_STANDBY_INIT); + + /* enable the OCP master ports and disable MStandby */ + ret = pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT, 0); + if (ret) + return ret; + + /* wait till we are ready for transactions - delay is arbitrary */ + for (i = 0; i < 10; i++) { + ret = pruss_cfg_read(pruss, PRUSS_CFG_SYSCFG, &syscfg_val); + if (ret) + goto disable; + + if (!(syscfg_val & SYSCFG_SUB_MWAIT_READY)) + return 0; + + udelay(5); + } + + dev_err(pruss->dev, "timeout waiting for SUB_MWAIT_READY\n"); + ret = -ETIMEDOUT; + +disable: + pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT, + SYSCFG_STANDBY_INIT); + return ret; +} +EXPORT_SYMBOL_GPL(pruss_cfg_ocp_master_ports); + static void pruss_of_free_clk_provider(void *data) { struct device_node *clk_mux_np = data; @@ -570,6 +641,10 @@ static const struct pruss_private_data am437x_pruss0_data = { .has_no_sharedram = true, }; +static const struct pruss_private_data am57xx_data = { + .has_ocp_syscfg = true, +}; + static const struct pruss_private_data am65x_j721e_pruss_data = { .has_core_mux_clock = true, }; @@ -578,7 +653,7 @@ static const struct of_device_id pruss_of_match[] = { { .compatible = "ti,am3356-pruss" }, { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, }, { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, }, - { .compatible = "ti,am5728-pruss" }, + { .compatible = "ti,am5728-pruss", .data = &am57xx_data, }, { .compatible = "ti,k2g-pruss" }, { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, }, { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, }, diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h index 2e18fef1a2e1..15b3c9c58539 100644 --- a/include/linux/pruss_driver.h +++ b/include/linux/pruss_driver.h @@ -118,6 +118,7 @@ int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id, int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable); int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, bool enable); +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable); #else @@ -172,6 +173,11 @@ static inline int pruss_cfg_xfr_enable(struct pruss *pruss, return -EOPNOTSUPP; } +static int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_TI_PRUSS */ #endif /* _PRUSS_DRIVER_H_ */