From patchwork Mon Feb 8 14:08:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378707 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CB07BC433E0 for ; Mon, 8 Feb 2021 14:11:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8AD0A64E75 for ; Mon, 8 Feb 2021 14:11:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231882AbhBHOLp (ORCPT ); Mon, 8 Feb 2021 09:11:45 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57510 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231911AbhBHOJj (ORCPT ); Mon, 8 Feb 2021 09:09:39 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Serge Semin CC: Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , Maxime Coquelin , , , , , Subject: [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings Date: Mon, 8 Feb 2021 17:08:06 +0300 Message-ID: <20210208140820.10410-3-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Baikal-T1 SoC is equipped with two DW GMAC v3.73a-based 1GBE ethernet interfaces synthesized with: RGMII PHY interface, AXI-DMA and APB3 CSR, 16KB Tx/Rx FIFOs and PBL up to half of that, PTP, PMT, TCP/IP CoE, up to 4 outstanding AXI read/write requests, maximum AXI burst length of 16 beats, up to eight MAC address slots, one GPI and one GPO ports. Generic DW MAC/STMMAC driver will easily handle the DT-node describing the Baikal-T1 GMAC network devices, but the bindings still needs to be created to have a better understanding of what the interface looks like. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Rob, please note I couldn't declare the axi-config object properties constraints without specifying the properties type and description. If I remove them the dt_binding_check will curse with the error: >> .../baikal,bt1-gmac.yaml: properties:axi-config:properties:snps,blen: 'description' is a required property >> .../baikal,bt1-gmac.yaml: properties:axi-config:properties:snps,wr_osr_lmt: 'oneOf' conditional failed, one must be fixed: 'type' is a required property Additional properties are not allowed ('maximum' was unexpected) >> ... I did't know what to do with these errors, so I just created normal sub-node properties with stricter constraints than they are specified in the main snps,dwmac.yaml schema. Any suggestion what is a better way to apply additional constraints on sub-node properties? --- .../bindings/net/baikal,bt1-gmac.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml diff --git a/Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml b/Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml new file mode 100644 index 000000000000..30ab74a9023d --- /dev/null +++ b/Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/baikal,bt1-gmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Baikal-T1 DW GMAC Network Interface + +maintainers: + - Serge Semin + +description: + Baikal-T1 is equipped with two DW GMAC v3.73a network interfaces. Each of + them doesn't have any on-SoC PHY attached, but instead exports RGMII + interface to connect any compatible physical layer transceiver. + +select: + properties: + compatible: + contains: + const: baikal,bt1-gmac + + required: + - compatible + +allOf: + - $ref: "snps,dwmac.yaml#" + +properties: + compatible: + items: + - const: baikal,bt1-gmac + - const: snps,dwmac-3.73a + - const: snps,dwmac + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-names: + const: macirq + + clocks: + minItems: 4 + maxItems: 4 + + clock-names: + minItems: 4 + maxItems: 4 + contains: + enum: + - stmmaceth + - pclk + - tx + - ptp_ref + + ngpios: + description: + Baikal-T1 GMAC have been created with one GPI and one GPO ports + enabled. So there are total two GPIOs available. + const: 2 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + tx-internal-delay-ps: + description: + DW MAC Tx clocks generator has been designed to always add 2ns delay + of TXC with respect to TXD. + const: 2000 + + rx-fifo-depth: + const: 16384 + + tx-fifo-depth: + const: 16384 + + axi-config: + type: object + + properties: + snps,wr_osr_lmt: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Maximum write outstanding requests is limited with 4 + maximum: 3 + + snps,rd_osr_lmt: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Maximum read outstanding requests is limited with 4 + maximum: 3 + + snps,blen: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: AXI-bus burst length width is limited with just 4 bits + items: + enum: [16, 8, 4, 0] + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - resets + - reset-names + - phy-mode + +unevaluatedProperties: false + +examples: + - | + ethernet@1f05e000 { + compatible = "baikal,bt1-dwmac", "snps,dwmac-3.73a", "snps,dwmac"; + reg = <0x1f05e000 0x2000>; + #address-cells = <1>; + #size-cells = <2>; + + interrupts = <72>; + interrupt-names = "macirq"; + + clocks = <&ccu_sys 1>, <&ccu_axi 3>, <&ccu_sys 2>, <&ccu_sys 3>; + clock-names = "pclk", "stmmaceth", "tx", "ptp_ref"; + + resets = <&ccu_axi 3>; + reset-names = "stmmaceth"; + + ngpios = <2>; + + gpio-controller; + #gpio-cells = <2>; + + phy-mode = "rgmii-rxid"; + tx-internal-delay-ps = <2000>; + + rx-fifo-depth = <16384>; + tx-fifo-depth = <16384>; + + axi-config { + snps,wr_osr_lmt = <0x3>; + snps,rd_osr_lmt = <0x3>; + snps,blen = <0 0 0 0 16 8 4>; + }; + }; +... From patchwork Mon Feb 8 14:08:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378704 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D28DBC43381 for ; Mon, 8 Feb 2021 14:13:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9939764E2E for ; Mon, 8 Feb 2021 14:13:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231974AbhBHOMZ (ORCPT ); Mon, 8 Feb 2021 09:12:25 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57754 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232024AbhBHOKB (ORCPT ); Mon, 8 Feb 2021 09:10:01 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 03/16] net: stmmac: Introduce MAC core cleanup method Date: Mon, 8 Feb 2021 17:08:07 +0300 Message-ID: <20210208140820.10410-4-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In some DW MAC IP-core configurations and hardware setups it might be necessary not to reset the MAC while the device is probed and added to the system for a subsequent use. For instance having the MAC synthesized with GPIs and GPOs requires that, so the GPIOs state would be in a coherent state while GPIO-chip is registered in the kernel. Since for such configurations the reset is prohibited let's provide the MAC core cleanup method to get the basic core registers back to the initial state so further device initialization would work with the values it has been designed to expect. That method will be useful for devices with GPIOs support. For now we've got a chip with DW GMAC IP and GPIOs synthesied, so the cleanup method is added to the corresponding driver sub-module only. Signed-off-by: Serge Semin --- .../ethernet/stmicro/stmmac/dwmac1000_core.c | 33 +++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/hwif.h | 4 +++ 2 files changed, 37 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 6b9a4f54b93c..2af4c8ac6fb7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -21,6 +21,38 @@ #include "stmmac_pcs.h" #include "dwmac1000.h" +static void dwmac1000_core_clean(void __iomem *ioaddr) +{ + int idx; + + /* Clean the basic MAC registers up. Note the MAC interrupts are + * enabled by default after reset. Let's mask them out so not to have + * any spurious MAC-related IRQ generated during the cleanup + * procedure. + */ + writel(0x7FF, ioaddr + GMAC_INT_MASK); + writel(0, ioaddr + GMAC_CONTROL); + writel(0, ioaddr + GMAC_FRAME_FILTER); + writel(0, ioaddr + GMAC_HASH_HIGH); + writel(0, ioaddr + GMAC_HASH_LOW); + writel(0, ioaddr + GMAC_FLOW_CTRL); + writel(0, ioaddr + GMAC_VLAN_TAG); + writel(0, ioaddr + GMAC_DEBUG); + writel(0x80000000, ioaddr + GMAC_PMT); + writel(0, ioaddr + LPI_CTRL_STATUS); + writel(0x03e80000, ioaddr + LPI_TIMER_CTRL); + for (idx = 0; idx < 15; ++idx) { + writel(0x0000ffff, ioaddr + GMAC_ADDR_HIGH(idx)); + writel(0xffffffff, ioaddr + GMAC_ADDR_LOW(idx)); + } + writel(0, ioaddr + GMAC_PCS_BASE); + writel(0, ioaddr + GMAC_RGSMIIIS); + writel(0x1, ioaddr + GMAC_MMC_CTRL); + readl(ioaddr + GMAC_INT_STATUS); + readl(ioaddr + GMAC_PMT); + readl(ioaddr + LPI_CTRL_STATUS); +} + static void dwmac1000_core_init(struct mac_device_info *hw, struct net_device *dev) { @@ -511,6 +543,7 @@ static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable) } const struct stmmac_ops dwmac1000_ops = { + .core_clean = dwmac1000_core_clean, .core_init = dwmac1000_core_init, .set_mac = stmmac_set_mac, .rx_ipc = dwmac1000_rx_ipc_enable, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index b40b2e0667bb..3f5eed8333a5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -287,6 +287,8 @@ struct stmmac_est; /* Helpers to program the MAC core */ struct stmmac_ops { + /* MAC core cleanup */ + void (*core_clean)(void __iomem *ioaddr); /* MAC core initialization */ void (*core_init)(struct mac_device_info *hw, struct net_device *dev); /* Enable the MAC RX/TX */ @@ -396,6 +398,8 @@ struct stmmac_ops { bool enable); }; +#define stmmac_core_clean(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, core_clean, __args) #define stmmac_core_init(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, core_init, __args) #define stmmac_mac_set(__priv, __args...) \ From patchwork Mon Feb 8 14:08:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378701 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D11D2C433DB for ; Mon, 8 Feb 2021 14:14:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8E01564E60 for ; Mon, 8 Feb 2021 14:14:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231898AbhBHONZ (ORCPT ); Mon, 8 Feb 2021 09:13:25 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57760 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232053AbhBHOKH (ORCPT ); Mon, 8 Feb 2021 09:10:07 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 08/16] net: stmmac: Introduce Safety Feature IRQs enable/disable methods Date: Mon, 8 Feb 2021 17:08:12 +0300 Message-ID: <20210208140820.10410-9-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Safety feature IRQs is another set of IRQs, which aside with the DMA, MAC, MTL, GPIOs, etc interrupts can be generated by the DW *MAC network devices. They are signalled by means of the shared sbd_intr_o lane too, so we need to be able mask/unmask these interrupts in the framework of the generic IRQs setup procedure. Note there is no need in preserving the Safety interrupts enable register content in the provided callbacks as these registers are changed in these methods only. Moreover by doing so we disable the interrupts, which are unsupported by the Safety IRQ status handler, if any of them have been enabled by default. Signed-off-by: Serge Semin --- Folks, the zero initialization of the DW xGMAC XGMAC_MTL_ECC_CONTROL register looks suspicious. Are you sure it is supposed to be cleared out in order to enable the safety IRQs? --- .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 + drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 36 +++++++++-------- drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 2 + .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 40 +++++++++++-------- drivers/net/ethernet/stmicro/stmmac/hwif.h | 6 +++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++ 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 9ad48a0f96a6..99296ff14616 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -1320,6 +1320,8 @@ const struct stmmac_ops dwmac510_ops = { .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, .safety_feat_config = dwmac5_safety_feat_config, + .enable_safety_feat_irq = dwmac5_enable_safety_feat_irq, + .disable_safety_feat_irq = dwmac5_disable_safety_feat_irq, .safety_feat_irq_status = dwmac5_safety_feat_irq_status, .safety_feat_dump = dwmac5_safety_feat_dump, .rxp_config = dwmac5_rxp_config, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c index 8f7ac24545ef..43682a42b4d5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c @@ -190,7 +190,7 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp) if (!asp) return -EINVAL; - /* 1. Enable Safety Features */ + /* Enable Safety Features */ value = readl(ioaddr + MTL_ECC_CONTROL); value |= TSOEE; /* TSO ECC */ value |= MRXPEE; /* MTL RX Parser ECC */ @@ -199,30 +199,17 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp) value |= MTXEE; /* MTL TX FIFO ECC */ writel(value, ioaddr + MTL_ECC_CONTROL); - /* 2. Enable MTL Safety Interrupts */ - value = readl(ioaddr + MTL_ECC_INT_ENABLE); - value |= RPCEIE; /* RX Parser Memory Correctable Error */ - value |= ECEIE; /* EST Memory Correctable Error */ - value |= RXCEIE; /* RX Memory Correctable Error */ - value |= TXCEIE; /* TX Memory Correctable Error */ - writel(value, ioaddr + MTL_ECC_INT_ENABLE); - - /* 3. Enable DMA Safety Interrupts */ - value = readl(ioaddr + DMA_ECC_INT_ENABLE); - value |= TCEIE; /* TSO Memory Correctable Error */ - writel(value, ioaddr + DMA_ECC_INT_ENABLE); - /* Only ECC Protection for External Memory feature is selected */ if (asp <= 0x1) return 0; - /* 5. Enable Parity and Timeout for FSM */ + /* Enable Parity and Timeout for FSM */ value = readl(ioaddr + MAC_FSM_CONTROL); value |= PRTYEN; /* FSM Parity Feature */ value |= TMOUTEN; /* FSM Timeout Feature */ writel(value, ioaddr + MAC_FSM_CONTROL); - /* 4. Enable Data Parity Protection */ + /* Enable Data Parity Protection */ value = readl(ioaddr + MTL_DPP_CONTROL); value |= EDPP; writel(value, ioaddr + MTL_DPP_CONTROL); @@ -239,6 +226,23 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp) return 0; } +void dwmac5_enable_safety_feat_irq(void __iomem *ioaddr) +{ + /* Enable MTL Safety Interrupts: RX Parser Memory, EST, RX and Tx + * Memory Correctable Errors. + */ + writel(RPCEIE | ECEIE | RXCEIE | TXCEIE, ioaddr + MTL_ECC_INT_ENABLE); + + /* Enable DMA Safety Interrupts: TSO Memory Correctable Error. */ + writel(TCEIE, ioaddr + DMA_ECC_INT_ENABLE); +} + +void dwmac5_disable_safety_feat_irq(void __iomem *ioaddr) +{ + writel(0, ioaddr + MTL_ECC_INT_ENABLE); + writel(0, ioaddr + DMA_ECC_INT_ENABLE); +} + int dwmac5_safety_feat_irq_status(struct net_device *ndev, void __iomem *ioaddr, unsigned int asp, struct stmmac_safety_stats *stats) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h index 56b0762c1276..7709d206b6c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h @@ -99,6 +99,8 @@ #define GMAC_RXQCTRL_VFFQE BIT(16) int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp); +void dwmac5_enable_safety_feat_irq(void __iomem *ioaddr); +void dwmac5_disable_safety_feat_irq(void __iomem *ioaddr); int dwmac5_safety_feat_irq_status(struct net_device *ndev, void __iomem *ioaddr, unsigned int asp, struct stmmac_safety_stats *stats); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 3a93e1b10d2e..cdcc15b9d5e5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -834,28 +834,14 @@ static int dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp) if (!asp) return -EINVAL; - /* 1. Enable Safety Features */ + /* Enable Safety Features */ writel(0x0, ioaddr + XGMAC_MTL_ECC_CONTROL); - /* 2. Enable MTL Safety Interrupts */ - value = readl(ioaddr + XGMAC_MTL_ECC_INT_ENABLE); - value |= XGMAC_RPCEIE; /* RX Parser Memory Correctable Error */ - value |= XGMAC_ECEIE; /* EST Memory Correctable Error */ - value |= XGMAC_RXCEIE; /* RX Memory Correctable Error */ - value |= XGMAC_TXCEIE; /* TX Memory Correctable Error */ - writel(value, ioaddr + XGMAC_MTL_ECC_INT_ENABLE); - - /* 3. Enable DMA Safety Interrupts */ - value = readl(ioaddr + XGMAC_DMA_ECC_INT_ENABLE); - value |= XGMAC_DCEIE; /* Descriptor Cache Memory Correctable Error */ - value |= XGMAC_TCEIE; /* TSO Memory Correctable Error */ - writel(value, ioaddr + XGMAC_DMA_ECC_INT_ENABLE); - /* Only ECC Protection for External Memory feature is selected */ if (asp <= 0x1) return 0; - /* 4. Enable Parity and Timeout for FSM */ + /* Enable Parity and Timeout for FSM */ value = readl(ioaddr + XGMAC_MAC_FSM_CONTROL); value |= XGMAC_PRTYEN; /* FSM Parity Feature */ value |= XGMAC_TMOUTEN; /* FSM Timeout Feature */ @@ -864,6 +850,26 @@ static int dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp) return 0; } +void dwxgmac3_enable_safety_feat_irq(void __iomem *ioaddr) +{ + /* Enable MTL Safety Interrupts: RX Parser Memory, EST, RX and Tx + * Memory Correctable Errors. + */ + writel(XGMAC_RPCEIE | XGMAC_ECEIE | XGMAC_RXCEIE | XGMAC_TXCEIE, + ioaddr + XGMAC_MTL_ECC_INT_ENABLE); + + /* Enable DMA Safety Interrupts: Descriptor Cache, TSO Memory + * Correctable Errors. + */ + writel(XGMAC_DCEIE | XGMAC_TCEIE, ioaddr + XGMAC_DMA_ECC_INT_ENABLE); +} + +void dwxgmac3_disable_safety_feat_irq(void __iomem *ioaddr) +{ + writel(0, ioaddr + XGMAC_MTL_ECC_INT_ENABLE); + writel(0, ioaddr + XGMAC_DMA_ECC_INT_ENABLE); +} + static int dwxgmac3_safety_feat_irq_status(struct net_device *ndev, void __iomem *ioaddr, unsigned int asp, @@ -1510,6 +1516,8 @@ const struct stmmac_ops dwxgmac210_ops = { .debug = NULL, .set_filter = dwxgmac2_set_filter, .safety_feat_config = dwxgmac3_safety_feat_config, + .enable_safety_feat_irq = dwxgmac3_enable_safety_feat_irq, + .disable_safety_feat_irq = dwxgmac3_disable_safety_feat_irq, .safety_feat_irq_status = dwxgmac3_safety_feat_irq_status, .safety_feat_dump = dwxgmac3_safety_feat_dump, .set_mac_loopback = dwxgmac2_set_mac_loopback, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index b933347cd991..fc26169e24f8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -365,6 +365,8 @@ struct stmmac_ops { void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv); /* Safety Features */ int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp); + void (*enable_safety_feat_irq)(void __iomem *ioaddr); + void (*disable_safety_feat_irq)(void __iomem *ioaddr); int (*safety_feat_irq_status)(struct net_device *ndev, void __iomem *ioaddr, unsigned int asp, struct stmmac_safety_stats *stats); @@ -482,6 +484,10 @@ struct stmmac_ops { stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args) #define stmmac_safety_feat_config(__priv, __args...) \ stmmac_do_callback(__priv, mac, safety_feat_config, __args) +#define stmmac_enable_safety_feat_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, enable_safety_feat_irq, __args) +#define stmmac_disable_safety_feat_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, disable_safety_feat_irq, __args) #define stmmac_safety_feat_irq_status(__priv, __args...) \ stmmac_do_callback(__priv, mac, safety_feat_irq_status, __args) #define stmmac_safety_feat_dump(__priv, __args...) \ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 33065195c499..ddcd82d02c27 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4139,6 +4139,9 @@ static void stmmac_enable_irq(struct stmmac_priv *priv) maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); + if (priv->dma_cap.asp) + stmmac_enable_safety_feat_irq(priv, priv->ioaddr); + for (chan = 0; chan < maxq; ++chan) { stmmac_enable_dma_irq(priv, priv->ioaddr, chan); @@ -4176,6 +4179,9 @@ static void stmmac_disable_irq(struct stmmac_priv *priv) stmmac_disable_dma_irq(priv, priv->ioaddr, chan); } + if (priv->dma_cap.asp) + stmmac_disable_safety_feat_irq(priv, priv->ioaddr); + enable_irq(priv->dev->irq); } From patchwork Mon Feb 8 14:08:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378705 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3E022C433E0 for ; Mon, 8 Feb 2021 14:12:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DE99464E30 for ; Mon, 8 Feb 2021 14:12:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231148AbhBHOMH (ORCPT ); Mon, 8 Feb 2021 09:12:07 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57512 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231622AbhBHOJm (ORCPT ); Mon, 8 Feb 2021 09:09:42 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 09/16] net: stmmac: Disable MMC IRQs in the generic IRQs disable method Date: Mon, 8 Feb 2021 17:08:13 +0300 Message-ID: <20210208140820.10410-10-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org MMC IRQs aren't handled by the main ISR, so for the sake of the code coherency let's move the MMC IRQs disabling procedure to the generic IRQs de-activating method. By doing so we've finally finished filling the generic IRQs enable/disable functions up with the individual MAC/MTL/DMA/etc interrupt control methods. Signed-off-by: Serge Semin --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index ddcd82d02c27..fcd59a647b02 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2274,8 +2274,6 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv) unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; - stmmac_mmc_intr_all_mask(priv, priv->mmcaddr); - if (priv->dma_cap.rmon) { stmmac_mmc_ctrl(priv, priv->mmcaddr, mode); memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); @@ -4182,6 +4180,8 @@ static void stmmac_disable_irq(struct stmmac_priv *priv) if (priv->dma_cap.asp) stmmac_disable_safety_feat_irq(priv, priv->ioaddr); + stmmac_mmc_intr_all_mask(priv, priv->mmcaddr); + enable_irq(priv->dev->irq); } From patchwork Mon Feb 8 14:08:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378702 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7F824C43331 for ; Mon, 8 Feb 2021 14:13:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 586AF64EBC for ; Mon, 8 Feb 2021 14:13:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232314AbhBHOMg (ORCPT ); Mon, 8 Feb 2021 09:12:36 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57762 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232068AbhBHOKI (ORCPT ); Mon, 8 Feb 2021 09:10:08 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 10/16] net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP Date: Mon, 8 Feb 2021 17:08:14 +0300 Message-ID: <20210208140820.10410-11-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The flag name and semantics are misleading. Judging by the code the flag will be set only if the networking is requested for being reset, while logically in order to correctly reflect the device state the flag needs to be also set when the network device isn't opened. Let's convert the flag to having a positive meaning instead of keeping it being set all the time the interface is down. This modification will be also helpful for the case of the IRQs request being performed in the device probe method. So the driver could enable/disable the network-related IRQs handlers by synchronous flag switching together with the IRQs unmasking and masking. Luckily the IRQs are normally enabled/disable in the late/early network initialization stages respectively. Signed-off-by: Serge Semin --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index d88bc8af8eaa..ab8b1e04ed22 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -246,7 +246,7 @@ struct stmmac_priv { }; enum stmmac_state { - STMMAC_DOWN, + STMMAC_UP, STMMAC_RESET_REQUESTED, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index fcd59a647b02..f458d728825c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4151,6 +4151,8 @@ static void stmmac_enable_irq(struct stmmac_priv *priv) stmmac_enable_mac_irq(priv, priv->hw); + set_bit(STMMAC_UP, &priv->state); + enable_irq(priv->dev->irq); } @@ -4165,6 +4167,8 @@ static void stmmac_disable_irq(struct stmmac_priv *priv) disable_irq(priv->dev->irq); + clear_bit(STMMAC_UP, &priv->state); + stmmac_disable_mac_irq(priv, priv->hw); maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); @@ -4213,7 +4217,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) pm_wakeup_event(priv->device, 0); /* Check if adapter is up */ - if (test_bit(STMMAC_DOWN, &priv->state)) + if (!test_bit(STMMAC_UP, &priv->state)) return IRQ_HANDLED; /* Check if a fatal error happened */ if (stmmac_safety_feat_interrupt(priv)) @@ -4739,7 +4743,7 @@ static const struct net_device_ops stmmac_netdev_ops = { static void stmmac_reset_subtask(struct stmmac_priv *priv) { - if (test_bit(STMMAC_DOWN, &priv->state)) + if (!test_bit(STMMAC_UP, &priv->state)) return; netdev_err(priv->dev, "Reset adapter.\n"); @@ -4747,10 +4751,8 @@ static void stmmac_reset_subtask(struct stmmac_priv *priv) rtnl_lock(); netif_trans_update(priv->dev); - set_bit(STMMAC_DOWN, &priv->state); dev_close(priv->dev); dev_open(priv->dev, NULL); - clear_bit(STMMAC_DOWN, &priv->state); rtnl_unlock(); } From patchwork Mon Feb 8 14:08:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378706 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28ED0C433E9 for ; Mon, 8 Feb 2021 14:12:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D5B2E64E60 for ; Mon, 8 Feb 2021 14:12:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232347AbhBHOMC (ORCPT ); Mon, 8 Feb 2021 09:12:02 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57518 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231249AbhBHOJn (ORCPT ); Mon, 8 Feb 2021 09:09:43 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 11/16] net: stmmac: Add STMMAC state getter Date: Mon, 8 Feb 2021 17:08:15 +0300 Message-ID: <20210208140820.10410-12-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Since the STMMAC driver has internal STMMAC_UP flag declared to indicate the STMMAC network setup state, let's define the flag getter and use it in the driver code to get the current NIC state. We can also convert the netif_running() method invocation to calling the stmmac_is_up() function instead because the latter gives more accurate notion of the network state as the flag is set only after all the NIC initializations are finished. Signed-off-by: Serge Semin --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 4 ++- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 34 +++++++++++++------ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index ab8b1e04ed22..c993dcd1c7d9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -263,6 +263,7 @@ int stmmac_dvr_remove(struct device *dev); int stmmac_dvr_probe(struct device *device, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *res); +bool stmmac_is_up(struct stmmac_priv *priv); void stmmac_disable_eee_mode(struct stmmac_priv *priv); bool stmmac_eee_init(struct stmmac_priv *priv); int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 0ed287edbc2d..19debbd7f981 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -402,7 +402,9 @@ static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) static int stmmac_check_if_running(struct net_device *dev) { - if (!netif_running(dev)) + struct stmmac_priv *priv = netdev_priv(dev); + + if (!stmmac_is_up(priv)) return -EBUSY; return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f458d728825c..b37f49f3dc03 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2804,6 +2804,20 @@ static void stmmac_hw_teardown(struct net_device *dev) stmmac_mac_set(priv, priv->ioaddr, false); } +/** + * stmmac_is_up - test STMMAC state + * @priv: driver private structure + * Description: + * Detects the current network adapter state just by testing the MAC + * initialization completion flag. + * Return value: + * true if the STMMAC network is setup, false otherwise. + */ +bool stmmac_is_up(struct stmmac_priv *priv) +{ + return test_bit(STMMAC_UP, &priv->state); +} + /** * stmmac_open - open entry point of the driver * @dev : pointer to the device structure. @@ -4046,7 +4060,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) txfifosz /= priv->plat->tx_queues_to_use; - if (netif_running(dev)) { + if (stmmac_is_up(priv)) { netdev_err(priv->dev, "must be stopped to change its MTU\n"); return -EBUSY; } @@ -4217,7 +4231,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) pm_wakeup_event(priv->device, 0); /* Check if adapter is up */ - if (!test_bit(STMMAC_UP, &priv->state)) + if (!stmmac_is_up(priv)) return IRQ_HANDLED; /* Check if a fatal error happened */ if (stmmac_safety_feat_interrupt(priv)) @@ -4290,7 +4304,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct stmmac_priv *priv = netdev_priv (dev); int ret = -EOPNOTSUPP; - if (!netif_running(dev)) + if (!stmmac_is_up(priv)) return -EINVAL; switch (cmd) { @@ -4743,7 +4757,7 @@ static const struct net_device_ops stmmac_netdev_ops = { static void stmmac_reset_subtask(struct stmmac_priv *priv) { - if (!test_bit(STMMAC_UP, &priv->state)) + if (!stmmac_is_up(priv)) return; netdev_err(priv->dev, "Reset adapter.\n"); @@ -4915,7 +4929,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt) struct stmmac_priv *priv = netdev_priv(dev); int ret = 0; - if (netif_running(dev)) + if (stmmac_is_up(priv)) stmmac_release(dev); stmmac_napi_del(dev); @@ -4925,7 +4939,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt) stmmac_napi_add(dev); - if (netif_running(dev)) + if (stmmac_is_up(priv)) ret = stmmac_open(dev); return ret; @@ -4936,13 +4950,13 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size) struct stmmac_priv *priv = netdev_priv(dev); int ret = 0; - if (netif_running(dev)) + if (stmmac_is_up(priv)) stmmac_release(dev); priv->dma_rx_size = rx_size; priv->dma_tx_size = tx_size; - if (netif_running(dev)) + if (stmmac_is_up(priv)) ret = stmmac_open(dev); return ret; @@ -5253,7 +5267,7 @@ int stmmac_suspend(struct device *dev) struct stmmac_priv *priv = netdev_priv(ndev); u32 chan; - if (!ndev || !netif_running(ndev)) + if (!stmmac_is_up(priv)) return 0; phylink_mac_change(priv->phylink, false); @@ -5343,7 +5357,7 @@ int stmmac_resume(struct device *dev) struct stmmac_priv *priv = netdev_priv(ndev); int ret; - if (!netif_running(ndev)) + if (!stmmac_is_up(priv)) return 0; /* Power Down bit, into the PM register, is cleared From patchwork Mon Feb 8 14:08:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378703 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E500C4332E for ; Mon, 8 Feb 2021 14:13:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3725664E6C for ; Mon, 8 Feb 2021 14:13:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232560AbhBHOMl (ORCPT ); Mon, 8 Feb 2021 09:12:41 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57764 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232091AbhBHOKL (ORCPT ); Mon, 8 Feb 2021 09:10:11 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 12/16] net: stmmac: Introduce NIC software reset function Date: Mon, 8 Feb 2021 17:08:16 +0300 Message-ID: <20210208140820.10410-13-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Since we are about to move the IRQs handler setup into the device probe method, the DW MAC reset procedure needs to be redefined to be performed with care. We must make sure the IRQs handler isn't executed while the reset is proceeded and the IRQs are fully masked after that. The later is required for some early versions of DW GMAC (in our case it's DW GMAC v3.73a). Signed-off-by: Serge Semin --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b37f49f3dc03..c4c41b554c6a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1827,6 +1827,34 @@ static void free_dma_desc_resources(struct stmmac_priv *priv) free_dma_tx_desc_resources(priv); } +/** + * stmmac_sw_reset - reset the MAC/DMA/etc state + * @priv: driver private structure + * Description: Cleanup/reset the DW *MAC registers to their initial state. + */ +static int stmmac_sw_reset(struct stmmac_priv *priv) +{ + int ret; + + /* Disable the IRQ signal while the reset is in progress so not to + * interfere with what the main ISR is doing. + */ + disable_irq(priv->dev->irq); + + ret = stmmac_reset(priv, priv->ioaddr); + + /* Make sure all IRQs are disabled by default. Some DW MAC IP-cores + * like early versions of DW GMAC have MAC and MMC interrupts enabled + * after reset. + */ + if (!ret) + stmmac_disable_irq(priv); + + enable_irq(priv->dev->irq); + + return ret; +} + /** * stmmac_mac_enable_rx_queues - Enable MAC rx queues * @priv: driver private structure @@ -2340,9 +2368,9 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv) if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE)) atds = 1; - ret = stmmac_reset(priv, priv->ioaddr); + ret = stmmac_sw_reset(priv); if (ret) { - dev_err(priv->device, "Failed to reset the dma\n"); + dev_err(priv->device, "Failed to reset the core\n"); return ret; } From patchwork Mon Feb 8 14:08:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378700 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 18DC7C433E6 for ; Mon, 8 Feb 2021 14:14:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B197264E30 for ; Mon, 8 Feb 2021 14:14:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232180AbhBHONl (ORCPT ); Mon, 8 Feb 2021 09:13:41 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57768 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232425AbhBHOK4 (ORCPT ); Mon, 8 Feb 2021 09:10:56 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Jonathan Corbet , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , , Subject: [PATCH 14/16] net: stmmac: Add Generic DW MAC GPIO port driver Date: Mon, 8 Feb 2021 17:08:18 +0300 Message-ID: <20210208140820.10410-15-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> References: <20210208140820.10410-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Synopsys DesignWare Ethernet controllers can be synthesized with General-Purpose IOs support. GPIOs can work either as inputs or as outputs thus belong to the gpi_i and gpo_o ports respectively. The ports width (number of possible inputs/outputs) and the configuration registers layout depend on the IP-core version. For instance, DW GMAC can have from 0 to 4 GPIs and from 0 to 4 GPOs, while DW xGMAC have a wider ports width up to 16 pins of each one. In the framework of this driver both implementation can be supported as soon as the GPIO registers accessors are defined for the particular IP-core. Total number of GPIOs MAC supports can be passed via the platform descriptor. If it's a OF-based platform, then the standard "ngpios" DT-property will be parsed for it. Before registering the GPIO-chip in the kernel, the driver will try to auto-detect the number of GPIs and GPOs by writing 1s into the GPI type config register. Reading the written value back and calculating the number of actually set bits will give the GPI port width the device has been synthesized with. If GPIs have been detected then GPIO IRQ-chip will be also initialized and Only in that case the GPIO IRQs handling will be activated. Since the pending events are cleared just be reading from the GPI event status register, only the edged IRQs type can be implemented. For the same reason and for the reason of having the rest of GPIO configs reside in the same CSR, we had no choice but to define the GPI type, GPI mask and GPO state cache. So we wouldn't need to perform reading from the config register and accidentally clear pending GPI events in order to update these fields values. Note In case of GPIOs being available we can't reset the core otherwise the GPIO configs will be reset to the initial state too. Instead we suggest to at least restore the DMA/MAC registers to the initial state, when the software reset were supposed to happen. Signed-off-by: Serge Semin --- .../ethernet/stmicro/stmmac.rst | 4 + drivers/net/ethernet/stmicro/stmmac/Kconfig | 2 + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/hwif.c | 2 + drivers/net/ethernet/stmicro/stmmac/hwif.h | 14 + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 19 + .../net/ethernet/stmicro/stmmac/stmmac_gpio.c | 400 ++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 22 +- .../ethernet/stmicro/stmmac/stmmac_platform.c | 5 + include/linux/stmmac.h | 1 + 11 files changed, 470 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_gpio.c diff --git a/Documentation/networking/device_drivers/ethernet/stmicro/stmmac.rst b/Documentation/networking/device_drivers/ethernet/stmicro/stmmac.rst index 5d46e5036129..c0e6f1e7538c 100644 --- a/Documentation/networking/device_drivers/ethernet/stmicro/stmmac.rst +++ b/Documentation/networking/device_drivers/ethernet/stmicro/stmmac.rst @@ -495,6 +495,10 @@ is used to configure the AMBA bridge to generate more efficient STBus traffic:: int has_xgmac; +37) Total number of supported GPIOs:: + + u32 ngpios; + :: } diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 53f14c5a9e02..1d34672d4501 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -9,6 +9,8 @@ config STMMAC_ETH select CRC32 imply PTP_1588_CLOCK select RESET_CONTROLLER + select GPIOLIB + select GPIOLIB_IRQCHIP help This is the driver for the Ethernet IPs built around a Synopsys IP Core. diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 24e6145d4eae..71a59b513381 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \ stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \ - $(stmmac-y) + stmmac_gpio.o $(stmmac-y) stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 6f271c46368d..7d18ab71edd1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -466,6 +466,7 @@ struct mac_device_info { const struct stmmac_hwtimestamp *ptp; const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; + const struct stmmac_gpio_ops *gpio; const struct mdio_xpcs_ops *xpcs; struct mdio_xpcs_args xpcs_args; struct mii_regs mii; /* MII register Addresses */ diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index bb7114f970f8..067420059c11 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -101,6 +101,7 @@ static const struct stmmac_hwif_entry { const void *mode; const void *tc; const void *mmc; + const void *gpio; int (*setup)(struct stmmac_priv *priv); int (*quirks)(struct stmmac_priv *priv); } stmmac_hw[] = { @@ -319,6 +320,7 @@ int stmmac_hwif_init(struct stmmac_priv *priv) mac->mode = mac->mode ? : entry->mode; mac->tc = mac->tc ? : entry->tc; mac->mmc = mac->mmc ? : entry->mmc; + mac->gpio = mac->gpio ? : entry->gpio; priv->hw = mac; priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index fc26169e24f8..99c5841f1060 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -626,6 +626,20 @@ struct stmmac_mmc_ops { #define stmmac_mmc_read(__priv, __args...) \ stmmac_do_void_callback(__priv, mmc, read, __args) +/* Helpers for multi-core GPIO settings access */ +struct stmmac_gpio_ops { + void (*set_ctrl)(struct stmmac_priv *priv, u32 gpie, u32 gpit, u32 gpo); + void (*get_ctrl)(struct stmmac_priv *priv, u32 *gpie, u32 *gpit, u32 *gpo); + int (*get_gpi)(struct stmmac_priv *priv); +}; + +#define stmmac_gpio_set_ctrl(__priv, __args...) \ + stmmac_do_void_callback(__priv, gpio, set_ctrl, priv, __args) +#define stmmac_gpio_get_ctrl(__priv, __args...) \ + stmmac_do_void_callback(__priv, gpio, get_ctrl, priv, __args) +#define stmmac_gpio_get_gpi(__priv) \ + stmmac_do_callback(__priv, gpio, get_gpi, priv) + /* XPCS callbacks */ #define stmmac_xpcs_validate(__priv, __args...) \ stmmac_do_callback(__priv, xpcs, validate, __args) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index c993dcd1c7d9..c5b1150e2f66 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct stmmac_resources { @@ -97,6 +98,18 @@ struct stmmac_channel { u32 index; }; +struct stmmac_gpio { + struct gpio_chip gc; + u32 ngpis; + u32 ngpos; + struct { + u32 gpie; + u32 gpit; + u32 gpo; + } cache; + spinlock_t lock; +}; + struct stmmac_tc_entry { bool in_use; bool in_hw; @@ -231,6 +244,9 @@ struct stmmac_priv { struct workqueue_struct *wq; struct work_struct service_task; + /* General Purpose IO */ + struct stmmac_gpio gpio; + /* TC Handling */ unsigned int tc_entries_max; unsigned int tc_off_max; @@ -250,6 +266,9 @@ enum stmmac_state { STMMAC_RESET_REQUESTED, }; +int stmmac_gpio_add(struct stmmac_priv *priv); +bool stmmac_gpio_interrupt(struct stmmac_priv *priv); +void stmmac_gpio_remove(struct stmmac_priv *priv); int stmmac_mdio_unregister(struct net_device *ndev); int stmmac_mdio_register(struct net_device *ndev); int stmmac_mdio_reset(struct mii_bus *mii); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_gpio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_gpio.c new file mode 100644 index 000000000000..101e934a382b --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_gpio.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0-only +/******************************************************************************* + STMMAC Ethernet Driver -- GPI/GPO ports implementation + + Copyright (C) 2020 BAIKAL ELECTRONICS, JSC + + Author: Serge Semin + Maintainer: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "hwif.h" +#include "stmmac.h" + +/* Synopsys DesignWare Ethernet controllers can be synthesized with + * General-Purpose IOs support. GPIOs can work either as inputs or as + * outputs thus belong to the gpi_i and gpo_o ports respectively. + * The ports width (number of possible inputs/outputs) and the configuration + * registers layout depend on the IP-core version. For instance, DW GMAC can + * have from 0 to 4 GPIs and from 0 to 4 GPOs, while DW xGMAC have a wider + * ports width up to 16 pins of each one. + * + * Note 1. DW Ethernet IP-core GPIs implementation is a bit weird. First of all + * the GPIs state is multiplexed with the edge-triggered interrupt status in + * the GPIO control/status register. That is in case of the falling or rising + * edge event the GPI status register field gets to preserve the latched state + * of the input pin until the next read from the register. So in order to read + * the actual state of the input pin we'd need to read the GPIO status register + * twice. But that also cause the race condition from the GPI IRQ handler and + * the GPIs get state callback to the GPI state field value, which alas can't + * be resolved. So it's highly recommended to use all the DW *MAC GPIs either + * as just inputs or as the source of IRQs. + * + * Note 2. Moreover the GPIs state configuration fields are mapped either to + * the GPIO control or the GPIO status register, which other than that also + * provides the settings like GPOs state, GPIs IRQ type/mask/unmask. Due to + * that we have no choice but to cache the registers state and use the cached + * values to update the denoted settings, so to prevent the racy reads of the + * GPIs. + * + * Note 3. Due to the multiplexed GPIs state and interrupt status, the + * driver may experience false repeated IRQs detection. That is if after + * reading the GPI status register and calling the interrupt handler a client + * device doesn't revert the IRQ lane state and some other GPI raises an + * interrupt, the driver will get to detect the previous IRQ again. Alas we + * can't do much about it, but to have a hardware designed in a way so the + * device causing the IRQs would get the input pin state back after the IRQ + * is handled. + * + * Note 4. The GPIOs state is cleared together with the DW *MAC controller + * reset. So if IP-core isn't fixed to prevent that behavior the core resets + * mustn't be performed to have a stable GPIs/GPOs interface. + */ + +static void stmmac_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&priv->gpio.lock, flags); + priv->gpio.cache.gpie &= ~BIT(irqd_to_hwirq(d)); + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + spin_unlock_irqrestore(&priv->gpio.lock, flags); +} + +static void stmmac_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&priv->gpio.lock, flags); + priv->gpio.cache.gpie |= BIT(irqd_to_hwirq(d)); + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + spin_unlock_irqrestore(&priv->gpio.lock, flags); +} + +static int stmmac_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmmac_priv *priv = gpiochip_get_data(gc); + irq_hw_number_t offset = irqd_to_hwirq(d); + unsigned long flags; + int ret = 0; + + if (offset >= priv->gpio.ngpis) + return -EINVAL; + + spin_lock_irqsave(&priv->gpio.lock, flags); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + priv->gpio.cache.gpit &= ~BIT(offset); + break; + case IRQ_TYPE_EDGE_FALLING: + priv->gpio.cache.gpit |= BIT(offset); + break; + default: + ret = -EINVAL; + goto err_unlock; + } + + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + +err_unlock: + spin_unlock_irqrestore(&priv->gpio.lock, flags); + + return ret; +} + +/** + * stmmac_gpio_interrupt - handle DW MAC GPIO interrupt + * @ndev: driver private structure + * Description: checks the latched-low and -high events status for each GPIs + * detected in the MAC and raises the generic IRQ-chip handler. + * Return: + * returns true if any enabled event has been detected, false otherwise. + */ +bool stmmac_gpio_interrupt(struct stmmac_priv *priv) +{ + struct gpio_chip *gc = &priv->gpio.gc; + irq_hw_number_t hwirq; + unsigned long status; + + /* Make sure we get to handle only the GPIs with unmasked + * latched-low/-high events and the GPI is latched in accordance with + * the type of the event. If for some reason the IRQ cause hasn't been + * cleared on the previous IRQ handler execution or the client device + * hasn't got the GPI state back, here we'll get a repeated false IRQ. + */ + spin_lock(&priv->gpio.lock); + + status = stmmac_gpio_get_gpi(priv) ^ priv->gpio.cache.gpit; + status &= priv->gpio.cache.gpie; + + spin_unlock(&priv->gpio.lock); + + for_each_set_bit(hwirq, &status, priv->gpio.ngpis) + generic_handle_irq(irq_find_mapping(gc->irq.domain, hwirq)); + + return !!status; +} + +static int stmmac_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + + if (offset < priv->gpio.ngpis) + return GPIO_LINE_DIRECTION_IN; + else if (offset < priv->plat->ngpios) + return GPIO_LINE_DIRECTION_OUT; + + return -EINVAL; +} + +static int stmmac_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + + if (offset >= priv->gpio.ngpis) + return -EINVAL; + + return 0; +} + +static int stmmac_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + + if (offset < priv->gpio.ngpis || offset >= priv->plat->ngpios) + return -EINVAL; + + gc->set(gc, offset, value); + + return 0; +} + +static int stmmac_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags; + int ret; + + if (offset >= priv->plat->ngpios) + return -EINVAL; + + spin_lock_irqsave(&priv->gpio.lock, flags); + + if (offset < priv->gpio.ngpis) { + if (priv->gpio.cache.gpie) + dev_warn_once(priv->device, + "Reading GPIs may cause IRQ missing\n"); + + /* Read twice to clear the latched state out and get the + * current input pin state. + */ + (void)stmmac_gpio_get_gpi(priv); + ret = stmmac_gpio_get_gpi(priv); + } else { + offset -= priv->gpio.ngpis; + ret = priv->gpio.cache.gpo; + } + + spin_unlock_irqrestore(&priv->gpio.lock, flags); + + return !!(ret & BIT(offset)); +} + +static int stmmac_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags, fs, val = 0; + + fs = __ffs(*mask); + + spin_lock_irqsave(&priv->gpio.lock, flags); + + if (fs <= priv->gpio.ngpis) { + if (priv->gpio.cache.gpie) + dev_warn_once(priv->device, + "Reading GPIs may cause IRQ missing\n"); + + /* Read twice to clear the latched state out and get the + * current input pin state. + */ + (void)stmmac_gpio_get_gpi(priv); + val = stmmac_gpio_get_gpi(priv); + } + + val |= (priv->gpio.cache.gpo << priv->gpio.ngpis); + + spin_unlock_irqrestore(&priv->gpio.lock, flags); + + bitmap_replace(bits, bits, &val, mask, priv->plat->ngpios); + + return 0; +} + +static void stmmac_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags; + + if (offset < priv->gpio.ngpis || offset >= priv->plat->ngpios) + return; + + offset -= priv->gpio.ngpis; + + spin_lock_irqsave(&priv->gpio.lock, flags); + + if (value) + priv->gpio.cache.gpo |= BIT(offset); + else + priv->gpio.cache.gpo &= ~BIT(offset); + + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + + spin_unlock_irqrestore(&priv->gpio.lock, flags); +} + +static void stmmac_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct stmmac_priv *priv = gpiochip_get_data(gc); + unsigned long flags, gpom, gpob; + + gpom = *mask >> priv->gpio.ngpis; + gpob = *bits >> priv->gpio.ngpis; + + spin_lock_irqsave(&priv->gpio.lock, flags); + + priv->gpio.cache.gpo = (priv->gpio.cache.gpo & ~gpom) | gpob; + + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + + spin_unlock_irqrestore(&priv->gpio.lock, flags); +} + +static int stmmac_gpio_data_init(struct stmmac_priv *priv) +{ + u32 tmp; + + /* GPIs auto-detection: save GPO state, set as many GPI type bits + * as possible, then read the written value back. The number of set + * bits will be the actual number of GPIs. Leave the GPI type field + * being initialized with ones (i.e. the inputs having latched-low + * type) to have the falling-edge IRQs by default. + */ + priv->gpio.cache.gpit = ~0; + stmmac_gpio_get_ctrl(priv, &tmp, &tmp, &priv->gpio.cache.gpo); + stmmac_gpio_set_ctrl(priv, priv->gpio.cache.gpie, + priv->gpio.cache.gpit, priv->gpio.cache.gpo); + stmmac_gpio_get_ctrl(priv, &priv->gpio.cache.gpie, + &priv->gpio.cache.gpit, &priv->gpio.cache.gpo); + + priv->gpio.ngpis = hweight_long(priv->gpio.cache.gpit); + + if (priv->gpio.ngpis > priv->plat->ngpios) { + dev_err(priv->device, "Invalid ngpios specified\n"); + return -EINVAL; + } + + priv->gpio.ngpos = priv->plat->ngpios - priv->gpio.ngpis; + + spin_lock_init(&priv->gpio.lock); + + dev_info(priv->device, "GPI: %u, GPO: %u\n", priv->gpio.ngpis, + priv->gpio.ngpos); + + return 0; +} + +/** + * stmmac_gpio_add - add DW MAC GPIO chip + * @ndev: driver private structure + * Description: register GPIO-chip handling the DW *MAC GPIs and GPOs + * Return: + * returns 0 on success, otherwise errno. + */ +int stmmac_gpio_add(struct stmmac_priv *priv) +{ + struct gpio_chip *gc = &priv->gpio.gc; + struct gpio_irq_chip *girq = &gc->irq; + int ret; + + if (!priv->plat->ngpios) + return 0; + + ret = stmmac_gpio_data_init(priv); + if (ret) + return ret; + + gc->label = dev_name(priv->device); + gc->parent = priv->device; + gc->owner = THIS_MODULE; + gc->base = -1; + gc->ngpio = priv->plat->ngpios; + gc->get_direction = stmmac_gpio_get_direction; + gc->direction_input = stmmac_gpio_direction_input; + gc->direction_output = stmmac_gpio_direction_output; + gc->get = stmmac_gpio_get; + gc->get_multiple = stmmac_gpio_get_multiple; + gc->set = stmmac_gpio_set; + gc->set_multiple = stmmac_gpio_set_multiple; + + if (priv->gpio.ngpis) { + girq = &gc->irq; + girq->chip = devm_kzalloc(priv->device, sizeof(*girq->chip), + GFP_KERNEL); + if (!girq->chip) + return -ENOMEM; + + girq->chip->irq_ack = dummy_irq_chip.irq_ack; + girq->chip->irq_mask = stmmac_gpio_irq_mask; + girq->chip->irq_unmask = stmmac_gpio_irq_unmask; + girq->chip->irq_set_type = stmmac_gpio_irq_set_type; + girq->chip->name = dev_name(priv->device); + girq->chip->flags = IRQCHIP_MASK_ON_SUSPEND; + + girq->handler = handle_edge_irq; + girq->default_type = IRQ_TYPE_NONE; + girq->num_parents = 0; + girq->parents = NULL; + girq->parent_handler = NULL; + } + + ret = gpiochip_add_data(gc, priv); + if (ret) + dev_err(priv->device, "Failed to register GPIO-chip\n"); + + return ret; +} + +/** + * stmmac_gpio_remove - remove DW MAC GPIO-chip + * @ndev: driver private structure + * Description: remove GPIO-chip registered for the DW *MAC GPIs and GPOs + */ +void stmmac_gpio_remove(struct stmmac_priv *priv) +{ + if (!priv->plat->ngpios) + return; + + gpiochip_remove(&priv->gpio.gc); +} diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d75c851721f7..0e89bd6a10a1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1841,7 +1841,16 @@ static int stmmac_sw_reset(struct stmmac_priv *priv) */ disable_irq(priv->dev->irq); - ret = stmmac_reset(priv, priv->ioaddr); + /* In case of GPIOs being available we can't reset the core otherwise + * GPOs will be reset to the initial state too. Instead let's at least + * restore the DMA/MAC registers to the initial state. + */ + if (priv->plat->ngpios) { + ret = stmmac_core_clean(priv, priv->ioaddr) ?: + stmmac_dma_clean(priv, priv->ioaddr); + } else { + ret = stmmac_reset(priv, priv->ioaddr); + } /* Make sure all IRQs are disabled by default. Some DW MAC IP-cores * like early versions of DW GMAC have MAC and MMC interrupts enabled @@ -4199,6 +4208,10 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) u32 queue; bool xmac; + /* To handle MAC GPIO interrupts */ + if (priv->gpio.ngpis) + stmmac_gpio_interrupt(priv); + /* Check if adapter is up */ if (!stmmac_is_up(priv)) return IRQ_HANDLED; @@ -5220,6 +5233,10 @@ int stmmac_dvr_probe(struct device *device, if (ret) goto error_request_irq; + ret = stmmac_gpio_add(priv); + if (ret) + goto error_gpio_add; + if (priv->hw->pcs != STMMAC_PCS_TBI && priv->hw->pcs != STMMAC_PCS_RTBI) { /* MDIO bus Registration */ @@ -5268,6 +5285,8 @@ int stmmac_dvr_probe(struct device *device, priv->hw->pcs != STMMAC_PCS_RTBI) stmmac_mdio_unregister(ndev); error_mdio_register: + stmmac_gpio_remove(priv); +error_gpio_add: stmmac_free_irq(priv); error_request_irq: stmmac_napi_del(ndev); @@ -5306,6 +5325,7 @@ int stmmac_dvr_remove(struct device *dev) if (priv->hw->pcs != STMMAC_PCS_TBI && priv->hw->pcs != STMMAC_PCS_RTBI) stmmac_mdio_unregister(ndev); + stmmac_gpio_remove(priv); stmmac_free_irq(priv); reset_control_assert(priv->plat->stmmac_rst); destroy_workqueue(priv->wq); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 7cbde9d99133..2a9952b64c31 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -566,6 +566,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) if (rc) goto error_dma_cfg_alloc; + /* Retrieve total number of supported GPIOs from the STMMAC DT-node. + * Amount of GPIs and GPOs will be auto-detected by the driver later. + */ + of_property_read_u32(np, "ngpios", &plat->ngpios); + /* All clocks are optional since the sub-drivers may use the platform * clocks pointers to preserve their own clock-descriptors. */ diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index cec970adaf2e..35f7a59e730a 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -204,5 +204,6 @@ struct plat_stmmacenet_data { bool vlan_fail_q_en; u8 vlan_fail_q; unsigned int eee_usecs_rate; + u32 ngpios; }; #endif