From patchwork Thu Jan 9 10:55:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13932385 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 849CD204C3C; Thu, 9 Jan 2025 10:56:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420213; cv=none; b=dZBZZsunnvIFJMxdqOwb9YEf4QeKOG17ge6mGiMFWDgLQhmGyocxvJAa+7koyb6gNPs+E6lT8FEA3qNpUgmF5YmMCiEAtV1DaXtHkhz7m/We5yg1Z7l6eLnjJrSKoooMozbb3PKQDpeQLnSlygIC8RXw+nNF8xZhNXCD3QO0Exw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420213; c=relaxed/simple; bh=xPXqSDZMzUUfYCgzAn46ou40xReND6qshKIYFoeWw6A=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Mk8kZV7eOPKg7cLZ0t4+QC66uy5BPGr87hd9m1k09z13YD36saaaj6+/8TPJOIWJw1QEBCHlDkeOKrf411HZFTcncuFZbSE4HzyVlPrrpiTPlfWk/nQwQIaF2UuLzsoQ5hS7lqa/AibYSQGq+AH2DcvfStgbQLUeZEvxmLEBRY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=ozuYq36f; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="ozuYq36f" 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=sFaixx0KzTSo8hAsW5gUn3OeAsZxPN2BYPc4qJiQZkA=; b=ozuYq36fJBzYIXYHY3Xb8voINH l2SZb6RhmEJu+Y+x2MjuWualyyfPhyjGofWjrPoaF+4vr4z07PLqGbUigBR/8Bfh0CMIOM24hAHpj sPAOzU9Tqtx6C/GZtPRdZqhZzf9KRdsUuQD75KohuAAkAHnKq85+WsAFLdTh9K9Jw4n1toxH+95wt SgkHKm2RHCo0aTMP5yjZgmWPNL47426Yy9Ruto6/u5SvnNrtVDq+XhcNj2JYw68tjGG2kPapXZ0uX 75T5S4ze0AfFmc5jESCpDF9JHFCQ/dvipBHFMVK/+cKYJZweLMMOB48qWmRURgFQ8lOxUNNwmdPr2 SaQmA+dQ==; Received: from [122.175.9.182] (port=16507 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tVqDV-0006Xj-2i; Thu, 09 Jan 2025 16:26:45 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 01/10] dt-bindings: net: ti: Adds device tree binding for DUAL-EMAC mode support on PRU-ICSS2 for AM57xx SOCs Date: Thu, 9 Jan 2025 16:25:51 +0530 Message-Id: <20250109105600.41297-2-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Murali Karicheri Signed-off-by: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- .../devicetree/bindings/net/ti,icss-iep.yaml | 6 + .../bindings/net/ti,icssm-prueth.yaml | 153 ++++++++++++++++++ .../bindings/net/ti,pruss-ecap.yaml | 32 ++++ .../devicetree/bindings/soc/ti/ti,pruss.yaml | 9 ++ 4 files changed, 200 insertions(+) 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..afacdb61a84c 100644 --- a/Documentation/devicetree/bindings/net/ti,icss-iep.yaml +++ b/Documentation/devicetree/bindings/net/ti,icss-iep.yaml @@ -8,18 +8,24 @@ title: Texas Instruments ICSS Industrial Ethernet Peripheral (IEP) module maintainers: - Md Danish Anwar + - Parvathi Pudi + - Basharath Hussain Khaja properties: compatible: oneOf: - items: - enum: + - ti,am5728-icss-iep - ti,am642-icss-iep - ti,j721e-icss-iep - const: ti,am654-icss-iep - const: ti,am654-icss-iep + - items: + - enum: + - 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..34d68619c086 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml @@ -0,0 +1,153 @@ +# 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 + + ecap: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to Enhanced Capture (eCAP) event for ICSS + + interrupts: + maxItems: 2 + description: + Interrupt specifiers to IRQ. + + interrupt-names: + items: + - const: rx_lre_hp + - const: rx_lre_lp + + ethernet-ports: + type: object + additionalProperties: false + + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + + patternProperties: + ^port@[0-1]$: + type: object + description: ICSSM PRUETH external ports + $ref: ethernet-controller.yaml# + unevaluatedProperties: false + + properties: + reg: + items: + - enum: [0, 1] + description: ICSSG PRUETH port number + + interrupts: + maxItems: 3 + + interrupt-names: + items: + - const: rx + - const: emac_ptp_tx + - const: hsr_ptp_tx + + ti,no-half-duplex: + type: boolean + description: + Disable half duplex operation on ICSSM MII port. + + required: + - reg + anyOf: + - required: + - port@0 + - required: + - port@1 + +required: + - compatible + - sram + - ti,mii-rt + - ti,iep + - 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>; + ecap = <&pruss2_ecap>; + interrupts = <20 2 2>, <21 3 3>; + interrupt-names = "rx_lre_hp", "rx_lre_lp"; + interrupt-parent = <&pruss2_intc>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + pruss2_emac0: 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"; + ti,no-half-duplex; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + pruss2_emac1: 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"; + ti,no-half-duplex; + /* 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..d42e636bf516 --- /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: + - | + pruss0_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..ddd65bd93aa1 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 Thu Jan 9 10:55:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13932386 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 10D502163B7; Thu, 9 Jan 2025 10:57:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420230; cv=none; b=plf6+z+hW9AMyRChQRb9Y06a1JKdgvjKbQp1sDbFBKQbuKKkdYR/Nd0FvJ0qGrRdoME6hSpPe8WJ/D6shlAadpjP3lyYmsyadcK5PzQci0jopZHw1iDs8DuIDQboLilaEEAibt/etMDRUVy2IIJ9ak3ePvgQaPue7Wqt4vFBdU0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420230; c=relaxed/simple; bh=/CdDVyTpIzXNkEMP8n63YJonKI3LuTjuHUJSC7LfiXA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Hyr5eg76gzV1TJpvDgKTZM0mo5reI7DQoj9QVQtkmKQtfBoyS4+QzrUmgzweY9lDNLdz+Wo+d/iFeH0SUp2VM3TH9syVnIAlhwpMWPeR/hjPB8UjhuW9I7Jmf1r6D7AyvajaCD59H9FjQ4J7xkaQ0Hv+6QE/6r0Wbl7NE7ulgZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=TJvjBhNH; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="TJvjBhNH" 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=wp8KnG6fOCr0vvzd09UJ4Fy8cw7pMT2Ly3VvW3xrbsQ=; b=TJvjBhNHh6m1ICMH+GJF1pO3+Y FVhBd7aFlKmQiZopIFx+BpfeedAIApoVbMi9S7h7b7A4l4wqv31VPJID/n/gB6RuNkFjRyOJvTF4T lseAL84vpSB8Rx80R7uV6Ydr3lVQZv4ElimaPOCRwRXZQHU6I00U9W4slSOzj5ZHtjoOFZNms7y0F C9iI2JdGQ773MZOI3AxCBSLhwR+1NcYbjMgqKWpldLajr5U7MNrzB5Sdmuy80A/qw53V2A7VPM5lo rZP7jrMFY7x3/cN8C4Cx63LrO4q1S0e2TLHh/bLryr1fVm0vVw2PJlqu+A6SiV9ckhfXcNUrUHykh L8A5PRlg==; Received: from [122.175.9.182] (port=16507 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tVqDm-0006Xj-2W; Thu, 09 Jan 2025 16:27:02 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 02/10] net: ti: prueth: Adds ICSSM Ethernet driver Date: Thu, 9 Jan 2025 16:25:52 +0530 Message-Id: <20250109105600.41297-3-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/net/ethernet/ti/Kconfig | 12 + drivers/net/ethernet/ti/Makefile | 3 + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 544 +++++++++++++++++++ drivers/net/ethernet/ti/icssm/icssm_prueth.h | 101 ++++ 4 files changed, 660 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..297eacb52fad --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -0,0 +1,544 @@ +// 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 - full/half duplex */ + 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 = 0; + + 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) + netdev_err(ndev, "failed to boot PRU: %d\n", 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); + + emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0); + if (!emac->phy_node) { + dev_err(prueth->dev, "couldn't find phy-handle\n"); + ret = -ENODEV; + goto free; + } + + ret = of_get_phy_mode(eth_node, &emac->phy_if); + if (ret) { + dev_err(prueth->dev, "could not get phy-mode property err %d\n", + ret); + goto free; + } + + /* connect PHY */ + emac->phydev = of_phy_connect(ndev, emac->phy_node, + &icssm_emac_adjust_link, 0, emac->phy_if); + if (!emac->phydev) { + dev_dbg(prueth->dev, "couldn't connect to phy %s\n", + emac->phy_node->full_name); + ret = -EPROBE_DEFER; + goto free; + } + + /* remove unsupported modes */ + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + + if (of_property_read_bool(eth_node, "ti,no-half-duplex")) { + 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: + prueth->emac[mac] = NULL; + + 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); + + prueth->emac[mac] = NULL; +} + +static const struct of_device_id prueth_dt_match[]; + +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, "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..539f9f2abf61 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -0,0 +1,101 @@ +/* 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 device_node *phy_node; + 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 Thu Jan 9 10:55:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13932387 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7A8E1215F7B; Thu, 9 Jan 2025 10:57:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420250; cv=none; b=fMOIHQtHn5+m9AQ1imj5bDsSyGhYgUZkep7nU7s35AM0VITIe0IBpTsAmOjPQIkrFrlcsQmgfcMT8W63sLRLw0ocfWKG+S3aQ+WorEo+zrCAb27sPKNsSfSppFHP2Uh0nA8e5uwrzaKM+bDVv0tOc++7UQpyfYVE1diymrgUf/w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736420250; c=relaxed/simple; bh=5Zs4qo+gFTSKgVmwrp6ndcQFsX6q2mVuMhCrYpOAdVY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WI5auUJJGnrF8aU9/ekO/DeAiPzpM/gfasabQunlZtcXFdjG8yeZq/rb2V9ZdjBAcHjLDpbgIChs72TG7rwOKQvNKhsl4B3oS6ZoL2pe6tzI2aw+pdEyDYqZWUQiNSxpEPCPvOQDFdunShlNDq8bpmx3wVl8nRF/0FCWBlbuO80= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=EjzLXT9E; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="EjzLXT9E" 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=AF2CWTiDzkgUQtOqXnd3ASZuv/L5v+hYoQgu/fAmaho=; b=EjzLXT9E0zjqfMYF/n6L9bGkKg Be6n907st0R6qo3N7lXlwOzodWfdFtt/W4tMWowrsjLz2szFAqwoiOvRijWvvLzpEM4ogwwUhRJd8 /tDXAK6fowIUMvoYBHuiEKt+B/mNJ6xAuyeh8iGELwtXPur5aVXMtwVmeRMmNkEOTA10zDi0rWGnV V2IzTIQxdTu/VyNreymezLcYgNev2iqrdudloJSE/nuHPa+T/86LyLZ6GSdkKBM/DDmNHxOmo1V77 veKdLP0mlc3HMVxcxWXIOp/25P9ythzEHAhMJuyWe0aUYaK2PM0u+jh3nCqI+BySrg/lN485INTPt LtmSH1Zw==; Received: from [122.175.9.182] (port=16507 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tVqE5-0006Xj-0U; Thu, 09 Jan 2025 16:27:21 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 03/10] net: ti: prueth: Adds PRUETH HW and SW configuration Date: Thu, 9 Jan 2025 16:25:53 +0530 Message-Id: <20250109105600.41297-4-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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 discriptors. 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/net/ethernet/ti/icssg/icssg_mii_rt.h | 6 + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 417 ++++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 91 ++++ drivers/net/ethernet/ti/icssm/icssm_switch.h | 257 ++++++++++++ 4 files changed, 769 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switch.h diff --git a/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h index 55a59bf5299c..91808a19a598 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h +++ b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h @@ -76,6 +76,12 @@ #define PRUSS_MII_RT_RX_FRMS_MAX (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) #define PRUSS_MII_RT_RX_FRMS_MIN_FRM (64) +/* 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 + 6) + /* for HSR and PRP */ #define PRUSS_MII_RT_RX_FRMS_MAX_FRM_LRE (PRUSS_MII_RT_RX_FRMS_MAX + \ ICSS_LRE_TAG_RCT_SIZE) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index 297eacb52fad..adb3e40faede 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -29,6 +29,309 @@ #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 + +/* 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 +420,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) netdev_err(ndev, "failed to boot PRU: %d\n", ret); /* start PHY */ phy_start(emac->phydev); - + prueth->emac_configured |= BIT(emac->port_id); return 0; } @@ -221,9 +533,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: @@ -312,6 +626,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; @@ -377,6 +692,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)) { @@ -397,6 +718,70 @@ 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->mem[PRUETH_MEM_OCMC].va = + (void __iomem *)gen_pool_alloc(prueth->sram_pool, + 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 = 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); @@ -405,7 +790,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; } } @@ -443,6 +828,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) @@ -465,6 +853,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, + 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) @@ -502,6 +905,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, + 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]) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 539f9f2abf61..d9fd481b6f2e 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -13,6 +13,11 @@ #include #include +#include "icssm_switch.h" + +/* 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 +29,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 - 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 +93,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,6 +129,15 @@ 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, +}; + /** * struct prueth_private_data - PRU Ethernet private data * @fw_pru: firmware names to be used for PRUSS ethernet usecases @@ -78,6 +164,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; @@ -88,6 +175,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; @@ -97,5 +187,6 @@ struct prueth { struct net_device *registered_netdevs[PRUETH_NUM_MACS]; unsigned int eth_type; + 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 Thu Jan 9 10:55:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13932414 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F16B2153FE; Thu, 9 Jan 2025 11:10:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736421049; cv=none; b=dua7j8XF9WRAS/hfWD4cg4YKfTH8f3tvddtJcIVPx1VgWzbFp1TvFdfxMTHObCKBZFg1OThUlJBbs3toMGOg25w8NiEGd8wHOV4XnOyhEhGO336t/tJGaAgDvGzrTiKnx1BW3ptRgB4Ry/Q/a7jHYMhyTXATcOruLT3zP5WxJCk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736421049; c=relaxed/simple; bh=ub/tGhNAJ2TaAnD6QXViVPs2/zPufTGPQj7mIPk5xO4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pay+v4/4BDDqJH4fOGb+GibAiAy84uUdA7/QdYoSwqfhbDlHS3OnZB4aUrh4cwzZY4rhmXzdHkMMQqE/su8oZiOXyOe9G6dOsQlbi3VFwDaNPw4gaL+ApqOfTPg5fRQFCROVHiDPU+57X6BaWG0onttDEiakoNEk2iKiE1s9RUM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=mNrWhgEO; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="mNrWhgEO" 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=UBzC6VaKjxkkO3d5npDCX8MdgSn+KDla/bC4c43jt4w=; b=mNrWhgEOOMtFxRgteOs3J8YeVb hAkY2fysvMtv4aU9D/kFynWzCeYBym6mzMz/Czc660WG6XPAVeAbRfnpC6D98by3QFbOCz3x6Jqoo J/1KcMJuRVNSYhtCAm9pD66erepJUFDyWP9Mpda54ebitHHmSS+mNDa6PglsugsRqOE853IVhekGd 0E1wPN8LlMmhDWztYiMCCL1TgTW0wtTpKMDYw/RgW7ktORqSEII2JNEhAZOn8z2FySR0rN8excrzD bUlw6ivO/MMb3moMCgPThagFilVEgBfrV/CVaGXaZEhs/Uisms7JsZqSa81l+69xWp7MGjo0ovkLw di3EtE+A==; Received: from [122.175.9.182] (port=16507 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tVqEL-0006Xj-30; Thu, 09 Jan 2025 16:27:38 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 04/10] net: ti: prueth: Adds link detection, RX and TX support. Date: Thu, 9 Jan 2025 16:25:54 +0530 Message-Id: <20250109105600.41297-5-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/net/ethernet/ti/icssm/icssm_prueth.c | 611 ++++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 46 +- 2 files changed, 651 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index adb3e40faede..3112135e0641 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -35,6 +35,14 @@ #define TX_START_DELAY 0x40 #define TX_CLK_DELAY_100M 0x6 +#define TX_CLK_DELAY_10M 0 + +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); +} /* 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, @@ -292,18 +300,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); @@ -324,6 +345,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); @@ -333,6 +357,45 @@ 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); + + if (phy_speed == SPEED_10) + delay = TX_CLK_DELAY_10M; + else + 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->duplex == DUPLEX_HALF) + port_status |= PORT_IS_HD_MASK; + 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) { @@ -362,6 +425,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); @@ -377,6 +442,374 @@ static void icssm_emac_adjust_link(struct net_device *ndev) spin_unlock_irqrestore(&emac->lock, flags); } +/** + * 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; + u16 bd_rd_ptr, bd_wr_ptr, update_wr_ptr; + 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; + 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"); + 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 = txqueue->buffer_desc_end - + txqueue->buffer_desc_offset; + buffer_desc_count /= BD_SIZE; + buffer_desc_count++; + + bd_rd_ptr = readw(&queue_desc->rd_ptr); + bd_wr_ptr = readw(&queue_desc->wr_ptr); + + /* 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 + */ + write_block = (bd_wr_ptr - txqueue->buffer_desc_offset) / BD_SIZE; + read_block = (bd_rd_ptr - txqueue->buffer_desc_offset) / BD_SIZE; + 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 + bd_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); +} + +/* get packet from queue + * negative for error + */ +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 = rxqueue->buffer_desc_end - + rxqueue->buffer_desc_offset; + buffer_desc_count /= BD_SIZE; + buffer_desc_count++; + 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) { @@ -405,6 +838,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 = 0; + + 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; } @@ -435,10 +883,27 @@ static int icssm_emac_ndo_open(struct net_device *ndev) if (ret) netdev_err(ndev, "failed to boot PRU: %d\n", 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; } /** @@ -452,18 +917,128 @@ 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 and tx interrupts */ + if (emac->tx_irq > 0) + free_irq(emac->tx_irq, ndev); + + 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: success(NETDEV_TX_OK) or error code (typically out of desc's) + */ +static int icssm_emac_ndo_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret = 0; + u16 qid; + + if (unlikely(!emac->link)) { + if (netif_msg_tx_err(emac) && net_ratelimit()) + netdev_err(ndev, "No link to transmit"); + goto fail_tx; + } + + 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) { + /* no free TX queue */ + if (emac->tx_irq > 0) + netif_stop_queue(ndev); + 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 */ @@ -533,16 +1108,42 @@ 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; + } + emac->tx_irq = of_irq_get_byname(eth_node, "tx"); + if (emac->tx_irq < 0) { + if (emac->tx_irq != -EPROBE_DEFER) + dev_dbg(prueth->dev, "tx irq not configured\n"); + } + /* 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 d9fd481b6f2e..a818c0e49155 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -17,6 +17,11 @@ /* 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 + 6) /* PRU Ethernet Type - Ethernet functionality (protocol * implemented) provided by the PRU firmware being loaded. @@ -73,6 +78,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 + * @timstamp: 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. @@ -154,18 +185,25 @@ struct prueth_private_data { struct prueth_emac { struct prueth *prueth; struct net_device *ndev; - struct device_node *phy_node; 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; + int tx_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 */ @@ -189,4 +227,10 @@ struct prueth { unsigned int eth_type; 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 Jan 10 05:59:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933715 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7C38206F1A; Fri, 10 Jan 2025 06:00:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488827; cv=none; b=ioXOSpXtIsWB2BQhhDHz85mdHUmK+gSPPEXwD96EkxtzJ7dPoRMloPx4cgu+fHir0y84F3RP2beJXfgNl2974cKq7fXn2ZO3wU37jzTmjjgmg6V8194CbTj0oSoIZc0slXaVDYaqWPfSOJ4D4O2QzJsYX81zi5mj3PhaMhwRZUs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488827; c=relaxed/simple; bh=kXsUD1QciD0xB/qjVdkGO2k43yVy6Bsyu6Tlh0feR1Y=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TMsh1cw5brkjYsfxBsC2x4HLeV1e+yGhko/2LMcHCQbI7e/2akFdFEBeod2XDGjjJD+znXDy2tC2kzRkX15wxU3+Gi1IOBJTYlapvJ7x82SWMjJWsbHNZnOz1gCv9C4hRrOzCmS9QbRMKwuccmv1L30C/1oB7VyuCkankde3CGc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=O0UO1UfW; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="O0UO1UfW" 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=MrQ31d1bY/cKpDYWBrbItZRfGT2L+q8R8FcHhJHpDDk=; b=O0UO1UfWN6ncL0JcJMfMI6oIl0 ATZbYt1U/ACyZTV5Kcn5jChMEf5ibdUTknLyc7QV5Er/XZz7a+jYodh2gbs7NBR6mwgOSraowit0i TM7gzSbFS6SXzQ4kPh8h9jfsymb9eRYh3c5MPVLe+KeI/8RTLP9WDtgvrdKVqLxNxJcF/dGjJoNm1 Sr6yJHdAwGjsGCIfexTHrxTcwwWyTdrteI2uJLNDO7tXRUgQ103TpG0F1AMdjQVLVNVVESNcIHGF7 UAp61Imx8HeQQ6BFug7QFw1uS9atiid2P5gZHAa8FqYNiZWnF8OU1O5R8RIVgLlV6vVhU3Fd5MoBG 6mEXY+hw==; Received: from [122.175.9.182] (port=1293 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW844-0001E8-1q; Fri, 10 Jan 2025 11:30:12 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 05/10] net: ti: prueth: Adds ethtool support for ICSSM PRUETH Driver Date: Fri, 10 Jan 2025 11:29:01 +0530 Message-Id: <20250110055906.65086-6-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/net/ethernet/ti/Makefile | 2 +- drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 203 ++++++++++++++++++ drivers/net/ethernet/ti/icssm/icssm_prueth.c | 31 +++ drivers/net/ethernet/ti/icssm/icssm_prueth.h | 127 +++++++++++ 4 files changed, 362 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..cce3276d5565 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments ICSSM Ethernet Driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#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); +} + +/* 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, +}; +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 3112135e0641..d65676202e7c 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -879,6 +879,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) netdev_err(ndev, "failed to boot PRU: %d\n", ret); @@ -930,6 +932,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 and tx interrupts */ if (emac->tx_irq > 0) free_irq(emac->tx_irq, ndev); @@ -1035,10 +1039,36 @@ static int icssm_emac_ndo_start_xmit(struct sk_buff *skb, return ret; } +/** + * icssm_emac_ndo_get_stats - EMAC get statistics function + * @ndev: The EMAC network adapter + * + * Called when system wants to get statistics from the device. + * + * We return the statistics in net_device_stats structure pulled from emac + * + * Return: stats + */ +static struct net_device_stats +*icssm_emac_ndo_get_stats(struct net_device *ndev) +{ + struct net_device_stats *stats = &ndev->stats; + struct prueth_emac *emac = netdev_priv(ndev); + struct port_statistics pstats; + + icssm_emac_get_stats(emac, &pstats); + stats->collisions = pstats.late_coll + pstats.single_coll + + pstats.multi_coll + pstats.excess_coll; + stats->multicast = pstats.rx_mcast; + + return stats; +} + 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_stats = icssm_emac_ndo_get_stats, }; /* get emac_port corresponding to eth_node name */ @@ -1190,6 +1220,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 a818c0e49155..3af5b5d87702 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -23,6 +23,12 @@ */ #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + 6) +#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. */ @@ -104,6 +110,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. @@ -190,6 +309,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; @@ -228,9 +348,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 Jan 10 05:59:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933716 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 422BE204688; Fri, 10 Jan 2025 06:00:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488861; cv=none; b=uQE+uprkLJI/QtWqpSKkHMQDqT6gidHb+vCjT9+9IAjEIS5gW/eBE+bF8T0nuqPo3XxA6uUZuk4iJ+JSrbGqUWG8JIlmju3YWpuvNnzz34YCUBEkbvlyCjJc4Wfo3o8ImcJSx3uei0u5xu9yy5RdnvgbN/Y28FeZG9J39tsslOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488861; c=relaxed/simple; bh=xPdUxSD2M1LzPKGTXiUnCE2hpJs58KOHcyTYtEl/edc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jYfqPvNDq3z6zUX4tmmm3Pyy/BP2o2XphLPGvPismp2Rwkr5XpDEVm5zhvM4bBFa8TR9Ozi6t5OhxTvr2fXOKWqO3jpiPP07BWBhFhX0jLCBnExjXP67nZdfbRSRsBMozTOxi5yWVTpLqh9oF6ATGWcjy1HVtQhdrfwvmM1LjiA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=hyu0FIK2; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="hyu0FIK2" 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=fFPSYWB+dj5rUDCPMS4NRIlZQAtSUKFR2auGoWr8HsM=; b=hyu0FIK2t/awRIGuL6dFiuq1R3 tFhAZ+QP5GyTCm6TVb6tbRZ4BwNabdg5wnsNZRRziIjW4Pq/p2JCtgD4kQ5RrYV8LAkIy82PV6hWB QWbpj2HZGOc3KF2uSIPWcsBnmRWPonQcGyms2Byd7JZBEZm2ZsNTWFV4AJiL7ag8SA+cNE1sOIvrR QnvXQF80iaiCC+JMtD19GwckqcfPIEMEHepUJUg/6iYcf3c9eLxENXRiPKyW10OusvyMp9SKhF5se Hy1i3Bbuzd0zg+sApY+SO/VIGf/tqZmqb400PCBgW7cCxm8fnP5D4kCyOV43d5pDK77mF9EHCN45c arfEXMIQ==; Received: from [122.175.9.182] (port=1293 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW84i-0001E8-0h; Fri, 10 Jan 2025 11:30:52 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 06/10] net: ti: prueth: Adds HW timestamping support for PTP using PRU-ICSS IEP module Date: Fri, 10 Jan 2025 11:29:02 +0530 Message-Id: <20250110055906.65086-7-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- drivers/net/ethernet/ti/icssg/icss_iep.c | 42 ++ drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 26 + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 443 +++++++++++++++++- drivers/net/ethernet/ti/icssm/icssm_prueth.h | 11 + .../net/ethernet/ti/icssm/icssm_prueth_ptp.h | 85 ++++ 5 files changed, 605 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 cce3276d5565..86d62d64dc4d 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -7,6 +7,7 @@ #include #include "icssm_prueth.h" +#include "../icssg/icss_iep.h" #define PRUETH_MODULE_VERSION "0.2" #define PRUETH_MODULE_DESCRIPTION "PRUSS Ethernet driver" @@ -189,12 +190,37 @@ static void icssm_emac_get_regs(struct net_device *ndev, regs->version = PRUETH_REG_DUMP_GET_VER(prueth); } +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_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + 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, .get_link_ksettings = icssm_emac_get_link_ksettings, .set_link_ksettings = icssm_emac_set_link_ksettings, .get_link = ethtool_op_get_link, + .get_ts_info = icssm_emac_get_ts_info, .get_sset_count = icssm_emac_get_sset_count, .get_strings = icssm_emac_get_strings, .get_ethtool_stats = icssm_emac_get_ethtool_stats, diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c index d65676202e7c..b7b0181ffcb6 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) @@ -44,6 +45,45 @@ static inline void icssm_prueth_write_reg(struct prueth *prueth, writel_relaxed(val, prueth->mem[region].va + reg); } +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 }; @@ -442,6 +482,173 @@ static void icssm_emac_adjust_link(struct net_device *ndev) spin_unlock_irqrestore(&emac->lock, flags); } +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 sane 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 * @@ -552,6 +759,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; @@ -593,6 +806,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; @@ -602,6 +816,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 @@ -614,6 +829,8 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, buffer_desc_count++; 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; @@ -681,9 +898,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 *)roundup((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(); @@ -854,9 +1084,64 @@ 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"); + free_irq(emac->rx_irq, ndev); + free_irq(emac->tx_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 @@ -881,9 +1166,20 @@ 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) + if (ret) { netdev_err(ndev, "failed to boot PRU: %d\n", ret); + goto iep_exit; + } ret = icssm_emac_request_irqs(emac); if (ret) @@ -905,6 +1201,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; } @@ -920,6 +1220,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); @@ -929,16 +1230,35 @@ 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 and tx interrupts */ if (emac->tx_irq > 0) free_irq(emac->tx_irq, ndev); 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"); @@ -1039,6 +1359,30 @@ static int 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_stats - EMAC get statistics function * @ndev: The EMAC network adapter @@ -1064,11 +1408,86 @@ static struct net_device_stats return stats; } +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_stats = icssm_emac_ndo_get_stats, + .ndo_eth_ioctl = icssm_emac_ndo_ioctl, }; /* get emac_port corresponding to eth_node name */ @@ -1174,6 +1593,14 @@ static int icssm_prueth_netdev_init(struct prueth *prueth, dev_dbg(prueth->dev, "tx irq not configured\n"); } + 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)) { @@ -1437,12 +1864,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] = @@ -1476,6 +1910,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]; @@ -1547,6 +1984,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 3af5b5d87702..9ff70cbf5963 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" /* PRUSS local memory map */ #define ICSS_LOCAL_SHARED_RAM 0x00010000 @@ -327,6 +328,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 { @@ -336,6 +343,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; @@ -356,6 +364,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 Jan 10 05:59:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933717 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 778DB2066CB; Fri, 10 Jan 2025 06:01:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488890; cv=none; b=o7JSZcOsuq2mUOsbLP8gW+v2mLCPTNJkssUjLGTbb5x04xyMdX9S/6WDxfg4lgrEincw/l1hjRSYJW7B5SGpZYzwhdBn1l6BcQiaVfunNi3pbTUhHXp76IsRv6l/APwv1zP3o1b29Pl5ObzBYETkBIWn4IC2kaP0FJZNolz/+M4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736488890; c=relaxed/simple; bh=4lzrWxaPCMxchtIJ+sLmzRadQsv50KidBDONMUHUIiY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Dt9f8wmmkuUoVKbGSu1ZCwupaq9Cixo9oMRd3htivOf6/9u8V2WT3jyuAZPxhKNS39y87HKs++ezxK6c0uK9aDOsu4LN0xAPzIcrodQWhwpUDTi0C5FrfDM8oqLyPkh6o8I6s39g3VUv3IRMWLYhkeYkqo1SnzjeF+yfCEcIRII= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=gKZXzVO1; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="gKZXzVO1" 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=UGLRUFgumU5nJaLIDLolkBBTeLvspCMVxBm0+sz7Zcs=; b=gKZXzVO1eZK8dUMrazV49tRlhI pFNqmlpWDj2cIcfNVrB/72oLcBOEz31nLQuQz5TRYMQF/gg5cLn9Uxu7T6z+6LB8/Sr8b1LwdmrTn naXr/oArZ3S6q41fdUs12s9CSbsEXMpctxoITwm5QK83f1ifTmSs0Ajpq1aytsQpMN7HDML8hqTM9 W8aOBp31dBQWaK/y3KdK5vi3E7Qp/x7NQ1lziq+jcWRkBcEaPD0A+UHwI+tDsAIoEafKr3T8SZIfv RX076gkKXnbD6O2f1j0Ngfle2Nr/e5b4h1C/axorlgOENY0xuhYg3PRXK4A366a2dM4IlcXJ8RbtI aVjJ8OYg==; Received: from [122.175.9.182] (port=1293 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW85B-0001E8-1r; Fri, 10 Jan 2025 11:31:21 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 07/10] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS Date: Fri, 10 Jan 2025 11:29:03 +0530 Message-Id: <20250110055906.65086-8-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- 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 86d62d64dc4d..73c947342e81 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -7,6 +7,7 @@ #include #include "icssm_prueth.h" +#include "icssm_vlan_mcast_filter_mmap.h" #include "../icssg/icss_iep.h" #define PRUETH_MODULE_VERSION "0.2" @@ -20,6 +21,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 */ @@ -30,6 +36,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); } /** @@ -181,13 +192,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 int icssm_emac_get_ts_info(struct net_device *ndev, @@ -225,5 +263,6 @@ const struct ethtool_ops emac_ethtool_ops = { .get_strings = icssm_emac_get_strings, .get_ethtool_stats = icssm_emac_get_ethtool_stats, .get_regs = icssm_emac_get_regs, + .get_regs_len = icssm_emac_get_regs_len, }; 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 b7b0181ffcb6..57fc887e4317 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" @@ -38,6 +39,26 @@ #define TX_CLK_DELAY_100M 0x6 #define TX_CLK_DELAY_10M 0 +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) @@ -337,18 +358,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) @@ -1408,6 +1436,174 @@ static struct net_device_stats return stats; } +/* 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) { @@ -1481,13 +1677,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_stats = icssm_emac_ndo_get_stats, + .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 */ @@ -1553,6 +1851,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) { @@ -1599,7 +1898,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); @@ -1646,6 +1947,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; @@ -1699,6 +2004,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) @@ -1894,6 +2200,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 9ff70cbf5963..6d16f249efa1 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -24,6 +24,9 @@ */ #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + 6) +/* 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 */ @@ -289,6 +292,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; +}; + /** * struct prueth_private_data - PRU Ethernet private data * @fw_pru: firmware names to be used for PRUSS ethernet usecases @@ -301,6 +327,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; @@ -326,8 +357,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 */ @@ -354,19 +393,27 @@ struct prueth { unsigned int eth_type; 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 Jan 10 07:13:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933869 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 154E917995E; Fri, 10 Jan 2025 07:14:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493294; cv=none; b=c9vIaqpEMH1RAaACg/sDyOKIbsVJvR1tDZlzkTRoIvJDG7evPggY9ttOxC/qaDyyuJ3APOg9m/P5JYyyOBuyONjaYOMl+PnmvknO+YlFXu7mvDu0MgR4EiS4SEGq169d1vfGWVHy4EpAI+mG2IR3Xx/NQ9HcHrst0+s8g4i6jwk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493294; c=relaxed/simple; bh=N0f3eqA9BpBaonuEK+dfcDH6PfLJaajd0EXEs7z4Qls=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VXZEfj9NIC7Nqs11990ltb6Eb/BsoK08j01CrN43m3Kqehx8mqpucb3L2vUaQK7txrjzFlSi/F8TkWpUenIAlsZ0mN0ql6KCVDKQ/HDt3DYwgrf/ktV39az3CbY6Lxh5MSkUAzfFTFfKj6bit/c2KLTSg4F4Mzc7zx3Src8ev8E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=IkA/hmr7; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="IkA/hmr7" 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=MS6+VrmQJ0k1U5nKIvUXbhlIV2XPEYOIqlRzaUo3bG4=; b=IkA/hmr7ewV0uDCULs2hxjRSpu gANmBycWO1siPkddICMBpzQT6a7SMNa5rHp5YRSxYxQxJQeXNHDDGu4MrcOvaqf3PWrhwOZ+yQb5P SFxCA9DL7ixjuqF4ZXslBMAuDze3NUyLNuC9jhrxFqktbtaepqfFamaPhQ7/FWMLYud6+6EJzc5cw qD2WelHmfaFslquXBj94vVwpxLawhNisX7mJlboUYJOBEAeSah4NLFQtNosY+AfneGcPNfvjhknvA LUaJNJl9ODHDWrzYURVlrb/mDORLK2Qlzkvr5z2JW2WgDc8K0kF6FM8bLt4giV4K+izfaL5aLSPwk 9zwnpmTw==; Received: from [122.175.9.182] (port=50142 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW9EC-0002S5-0n; Fri, 10 Jan 2025 12:44:44 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 08/10] net: ti: prueth: Adds support for RX interrupt coalescing/pacing Date: Fri, 10 Jan 2025 12:43:49 +0530 Message-Id: <20250110071351.66888-9-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- 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 73c947342e81..70491d5ec872 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c @@ -7,6 +7,7 @@ #include #include "icssm_prueth.h" +#include "icssm_prueth_ecap.h" #include "icssm_vlan_mcast_filter_mmap.h" #include "../icssg/icss_iep.h" @@ -252,6 +253,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, @@ -264,5 +299,8 @@ const struct ethtool_ops emac_ethtool_ops = { .get_ethtool_stats = icssm_emac_get_ethtool_stats, .get_regs = icssm_emac_get_regs, .get_regs_len = icssm_emac_get_regs_len, + .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 57fc887e4317..97de6b7ebd29 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" @@ -1182,8 +1183,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); @@ -1193,6 +1196,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); @@ -2177,12 +2183,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] = @@ -2218,6 +2237,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 6d16f249efa1..455e286946cb 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" @@ -384,6 +385,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; @@ -392,6 +394,7 @@ struct prueth { struct net_device *registered_netdevs[PRUETH_NUM_MACS]; unsigned int eth_type; + 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..ac0f227473b4 --- /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, "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 Jan 10 07:13:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933870 X-Patchwork-Delegate: kuba@kernel.org Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC34A206F1D; Fri, 10 Jan 2025 07:15:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493312; cv=none; b=LecU7CLEyBoe5c7nlDVckJp3qJqJbzoYmUVESaaUFsYTTTsRp+qHsZ2OSaM+Kj03JTCNOFh6NJG1sItGOrLhUfCNYJ3z2meYwVUnWm4H1LN6d6aTEzhn3L5Ib1/GgWWUPFABKJFgyGmkmHC9qbxhNrkyz/ihIZkJ2lESU0w3z88= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493312; c=relaxed/simple; bh=JNC2yPOyeQMQjS5PUzYcW+j1WQA4DgjgFwa6UTDbDhA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Wk+RImGuo/f8fzAOuYREqLHBfcl5O/oNWZFYus12Hq713Uw1duC7L0WD6diURZ+tq+kpuwtJBnsZayM/Ufn6w2V6VR0BEVkO7IaAVxIgKX+YuL1BsgTyo1lbQ4QfTw0H4dbdDWuEp/YR7XbpLC2kD5xvoFQkoy0ZkLtMlJ3ROLo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=ojvBWUYb; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="ojvBWUYb" 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=OJK9edcXiUw0RWX6sjEYfyqim2K+D1H/MN+6E+o7jTk=; b=ojvBWUYbLxsx2D5ovmnSfS7cf2 NOfAyK4zywukHHDet93UXwA6PATdU78WX68mT0CAYRWs/htvvGnJLGHDwAfYuduH+6pR0azuwfCqx gR875OvR0j1T8dWtROQgxT/AjJaE6U8ZEoM8fbegaq6JSO/rF7kiybFO3qdXjDXVEHZhPWiIn/14i 5DXcfCLq8rLqGeJPsVYnHiuE0ANX0aX7Z0a3/00znnMr4ryyNMr46w/hVwj83mIZ9ntcFQGtqf9hf fvoQx1bvvYTftV8EUx61s2T/eZ0+3KdHcdjMz/qksCk1WkOSqlFyJUVrZLqgdE1AgwgGFucntgXYc HLfQpuBg==; Received: from [122.175.9.182] (port=50142 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW9ET-0002S5-39; Fri, 10 Jan 2025 12:45:02 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 09/10] net: ti: prueth: Adds power management support for PRU-ICSS Date: Fri, 10 Jan 2025 12:43:50 +0530 Message-Id: <20250110071351.66888-10-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC 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: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- 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 97de6b7ebd29..7727975dab88 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c @@ -2325,6 +2325,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 = { .fw_pru[PRUSS_PRU0] = { @@ -2349,6 +2410,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 Jan 10 07:13:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Basharath Hussain Khaja X-Patchwork-Id: 13933871 Received: from server.wki.vra.mybluehostin.me (server.wki.vra.mybluehostin.me [162.240.238.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC46D188714; Fri, 10 Jan 2025 07:15:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.240.238.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493326; cv=none; b=nA9imSGxvhQSZIjbeH1tsJh8/wGRUNuPoKUDWQbuc6hPVDvOuhSdZo2Bz7BR/oOVPjMogDhEoc5g+lLr1ZssiOWh7h7ZEsrpM/hJx6Nq9hLbW9yYkXei9p/2BS+s6zRmrOR23ozXIuNveZxzZNqYxCp3oc28nZixehmZwX0Ih2Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736493326; c=relaxed/simple; bh=1DUdhbNHwf7Ihdy3qxNIg0dZKQEOY3tk5u6LH7jQ6h8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cEriDFxcBBwIWqmCwDVc68UAYhQrySS4gdaOp4tKC+/QZ9Ls3kWFZuS6UUaw/BBUfjdrlA5FGOOfxm/P3YkuLY5XqlQPTujJdFtrT2JDCuzeqEZpq5zfljZnzdNfiNksGTU6U24lhDW2RwD0ZC2VghEULH16bOU8Jupo/zm0i6A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com; spf=pass smtp.mailfrom=couthit.com; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b=1vWaqtnZ; arc=none smtp.client-ip=162.240.238.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=couthit.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=couthit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=couthit.com header.i=@couthit.com header.b="1vWaqtnZ" 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=13OJ8FEoXvsyKmdayUPqlnZCqEb78KeiDL7hDUKSu38=; b=1vWaqtnZpP4/MxtW3PrUtnBuWk rjNlapGGrHsUss3n5ly54PBe/AsILvLOWgbuWVf77/HEVN3jzyKIl/ggS0M7uLxx7gVuHtBCpoBmc axguzQ3lncK6uJdsTvRLljHFeQsxg1A62t5GmyPx0+gpznGKvjrQLXLCi1A8TY4+04p0MZq/IeAcA jovSYEqmpPsHP54Mk38PTvPTOqGcbPnUW5xM3eM5dIJRhpxBBiZXeAume/+RqqpEaXoZa+9Bq9Mvi gYno8ksvvSLFM0WSywzRpg3lTev78Wkt9K/KLHuCuWGrgJGIzGjmXVFFTNxc1oDMirwls7Im9lvX3 8c9mQdVw==; Received: from [122.175.9.182] (port=50142 helo=cypher.couthit.local) by server.wki.vra.mybluehostin.me with esmtpa (Exim 4.96.2) (envelope-from ) id 1tW9El-0002S5-0z; Fri, 10 Jan 2025 12:45:19 +0530 From: Basharath Hussain Khaja 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, tony@atomide.com, richardcochran@gmail.com, parvathi@couthit.com, basharath@couthit.com, schnelle@linux.ibm.com, rdunlap@infradead.org, 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, linux-omap@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: [RFC PATCH 10/10] arm: dts: ti: Adds device tree nodes for PRU Cores, IEP and eCAP modules of PRU-ICSS2 Instance. Date: Fri, 10 Jan 2025 12:43:51 +0530 Message-Id: <20250110071351.66888-11-basharath@couthit.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250109105600.41297-1-basharath@couthit.com> References: <20250109105600.41297-1-basharath@couthit.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 - vger.kernel.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: basharath@couthit.com X-Authenticated-Sender: server.wki.vra.mybluehostin.me: basharath@couthit.com X-Source: X-Source-Args: X-Source-Dir: X-Patchwork-State: RFC From: Roger Quadros The TI Sitara AM57xx series of devices consists of 2 PRU-ICSS instances (PRU-ICSS1 and PRU-ICSS2). This patch adds the device tree nodes for the PRU-ICSS2 instance to support DUAL-MAC mode of operation. Each PRU-ICSS instance consists of two PRU cores along with various peripherals such as the Interrupt Controller (PRU_INTC), the Industrial Ethernet Peripheral(IEP), the Real Time Media Independent Interface controller (MII_RT), and the Enhanced Capture (eCAP) event module. am57-pruss.dtsi - Adds IEP and eCAP peripheral as child nodes of the PRUSS subsystem node. am57xx-idk-common.dtsi - Adds PRU-ICSS2 instance node along with PRU eth port information and corresponding port configuration. It includes interrupt mapping for packet reception, HW timestamp collection, and PRU Ethernet ports in MII mode. am571x-idk.dts, am572x-idk.dts and am574x-idk.dts - GPIO configuration along with delay configuration for individual PRU Ethernet port. Signed-off-by: Roger Quadros Signed-off-by: Andrew F. Davis Signed-off-by: Murali Karicheri Signed-off-by: Parvathi Pudi Signed-off-by: Basharath Hussain Khaja --- arch/arm/boot/dts/ti/omap/am57-pruss.dtsi | 11 ++++ arch/arm/boot/dts/ti/omap/am571x-idk.dts | 8 ++- arch/arm/boot/dts/ti/omap/am572x-idk.dts | 10 +-- arch/arm/boot/dts/ti/omap/am574x-idk.dts | 10 +-- .../boot/dts/ti/omap/am57xx-idk-common.dtsi | 63 +++++++++++++++++++ 5 files changed, 93 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/ti/omap/am57-pruss.dtsi b/arch/arm/boot/dts/ti/omap/am57-pruss.dtsi index 46c5383f0eee..f73316625608 100644 --- a/arch/arm/boot/dts/ti/omap/am57-pruss.dtsi +++ b/arch/arm/boot/dts/ti/omap/am57-pruss.dtsi @@ -170,6 +170,17 @@ pruss2_iepclk_mux: iepclk-mux@30 { }; }; + pruss2_iep: iep@2e000 { + compatible = "ti,am5728-icss-iep"; + reg = <0x2e000 0x31c>; + clocks = <&pruss2_iepclk_mux>; + }; + + pruss2_ecap: ecap@30000 { + compatible = "ti,pruss-ecap"; + reg = <0x30000 0x60>; + }; + pruss2_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x58>; diff --git a/arch/arm/boot/dts/ti/omap/am571x-idk.dts b/arch/arm/boot/dts/ti/omap/am571x-idk.dts index 322cf79d22e9..02653b440585 100644 --- a/arch/arm/boot/dts/ti/omap/am571x-idk.dts +++ b/arch/arm/boot/dts/ti/omap/am571x-idk.dts @@ -214,5 +214,11 @@ &pruss1_mdio { }; &pruss2_mdio { - status = "disabled"; + reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + reset-delay-us = <2>; /* PHY datasheet states 1uS min */ +}; + +&pruss2_eth { + ti,pruss-gp-mux-sel = <4>, /* MII2, needed for PRUSS1_MII0 */ + <4>; /* MII2, needed for PRUSS1_MII1 */ }; diff --git a/arch/arm/boot/dts/ti/omap/am572x-idk.dts b/arch/arm/boot/dts/ti/omap/am572x-idk.dts index 94a738cb0a4d..54a8ccb9ca14 100644 --- a/arch/arm/boot/dts/ti/omap/am572x-idk.dts +++ b/arch/arm/boot/dts/ti/omap/am572x-idk.dts @@ -28,10 +28,12 @@ &mmc2 { pinctrl-2 = <&mmc2_pins_ddr_rev20>; }; -&pruss1_mdio { - status = "disabled"; +&pruss2_eth0_phy { + reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + reset-assert-us = <2>; /* PHY datasheet states 1uS min */ }; -&pruss2_mdio { - status = "disabled"; +&pruss2_eth1_phy { + reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + reset-assert-us = <2>; /* PHY datasheet states 1uS min */ }; diff --git a/arch/arm/boot/dts/ti/omap/am574x-idk.dts b/arch/arm/boot/dts/ti/omap/am574x-idk.dts index 47b9174d2353..47b6c6cb210c 100644 --- a/arch/arm/boot/dts/ti/omap/am574x-idk.dts +++ b/arch/arm/boot/dts/ti/omap/am574x-idk.dts @@ -40,10 +40,12 @@ &emif1 { status = "okay"; }; -&pruss1_mdio { - status = "disabled"; +&pruss2_eth0_phy { + reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + reset-assert-us = <2>; /* PHY datasheet states 1uS min */ }; -&pruss2_mdio { - status = "disabled"; +&pruss2_eth1_phy { + reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + reset-assert-us = <2>; /* PHY datasheet states 1uS min */ }; diff --git a/arch/arm/boot/dts/ti/omap/am57xx-idk-common.dtsi b/arch/arm/boot/dts/ti/omap/am57xx-idk-common.dtsi index 43e3623f079c..da94984f47b8 100644 --- a/arch/arm/boot/dts/ti/omap/am57xx-idk-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am57xx-idk-common.dtsi @@ -155,6 +155,54 @@ src_clk_x1: src_clk_x1 { compatible = "fixed-clock"; clock-frequency = <20000000>; }; + + /* 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>; + ecap = <&pruss2_ecap>; + interrupts = <20 2 2>, <21 3 3>; + interrupt-names = "rx_lre_hp", "rx_lre_lp"; + interrupt-parent = <&pruss2_intc>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + pruss2_emac0: 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"; + ti,no-half-duplex; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + pruss2_emac1: 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"; + ti,no-half-duplex; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; + +}; + +&pruss2_iep { + interrupt-parent = <&pruss2_intc>; + interrupts = <7 7 8>; + interrupt-names = "iep_cap_cmp"; }; &dra7_pmx_core { @@ -606,3 +654,18 @@ dpi_out: endpoint { }; }; }; + +&pruss2_mdio { + status = "okay"; + pruss2_eth0_phy: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&gpio3>; + interrupts = <30 IRQ_TYPE_EDGE_FALLING>; + }; + + pruss2_eth1_phy: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + }; +};