From patchwork Mon Feb 8 14:08:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379927 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=unavailable 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 7842DC4332B for ; Mon, 8 Feb 2021 14:18:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3366564E2E for ; Mon, 8 Feb 2021 14:18:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232950AbhBHOSK (ORCPT ); Mon, 8 Feb 2021 09:18:10 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57558 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231458AbhBHOJJ (ORCPT ); Mon, 8 Feb 2021 09:09:09 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , Maxime Coquelin , , , , , Subject: [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Date: Mon, 8 Feb 2021 17:08:05 +0300 Message-ID: <20210208140820.10410-2-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: netdev@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. So the DW MAC DT-node can be equipped with "ngpios" property, which can't have a value greater than 32, standard GPIO-related properties like "gpio-controller" and "#gpio-cells", and, if GPIs are supposed to be detected, IRQ-controller related properties. Signed-off-by: Serge Semin --- .../devicetree/bindings/net/snps,dwmac.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index bdc437b14878..fcca23d3727e 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -110,6 +110,23 @@ properties: reset-names: const: stmmaceth + ngpios: + description: + Total number of GPIOs the MAC supports. The property shall include both + the GPI and GPO ports width. + minimum: 1 + maximum: 32 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + mac-mode: $ref: ethernet-controller.yaml#/properties/phy-connection-type description: 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: 378979 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=unavailable 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 B372FC43331 for ; Mon, 8 Feb 2021 14:18:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8BB4B64E5A for ; Mon, 8 Feb 2021 14:18:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232986AbhBHOSN (ORCPT ); Mon, 8 Feb 2021 09:18:13 -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: netdev@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: 378976 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=unavailable 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 E5001C433E0 for ; Mon, 8 Feb 2021 14:21:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A7AE264E2F for ; Mon, 8 Feb 2021 14:21:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233028AbhBHOVC (ORCPT ); Mon, 8 Feb 2021 09:21:02 -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: netdev@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:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378978 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=unavailable 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 15E4FC433E0 for ; Mon, 8 Feb 2021 14:19:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C755264E30 for ; Mon, 8 Feb 2021 14:19:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232336AbhBHOS7 (ORCPT ); Mon, 8 Feb 2021 09:18:59 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57508 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231929AbhBHOJk (ORCPT ); Mon, 8 Feb 2021 09:09:40 -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 04/16] net: stmmac: Introduce DMA core cleanup method Date: Mon, 8 Feb 2021 17:08:08 +0300 Message-ID: <20210208140820.10410-5-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: netdev@vger.kernel.org Similarly to the MAC core cleanup method let's introduce the DMA core cleanup method, since we need have a way to get the DMA registers back to their initial state while the whole interface reset is unavailable for the particular DW MAC IP-core setup, like in case of GPIs and GPOs support. For now we've created the DMA cleanup method for the DW GMAC IP only, since the chip we've got has been equipped with that IP and we lack the documents to add and test the rest of the IPs support. Signed-off-by: Serge Semin --- drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 12 ++++++++++++ drivers/net/ethernet/stmicro/stmmac/hwif.h | 3 +++ 4 files changed, 17 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index 2a04d9d45160..bae63e1420f2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -246,6 +246,7 @@ static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt, const struct stmmac_dma_ops dwmac1000_dma_ops = { .reset = dwmac_dma_reset, + .clean = dwmac_dma_clean, .init = dwmac1000_dma_init, .init_rx_chan = dwmac_dma_init_rx, .init_tx_chan = dwmac_dma_init_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index fa919bf75e19..f6e759d039d7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -145,5 +145,6 @@ void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan); int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x, u32 chan); int dwmac_dma_reset(void __iomem *ioaddr); +void dwmac_dma_clean(void __iomem *ioaddr); #endif /* __DWMAC_DMA_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 6ddfc689e77b..2186e95d5aa4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -26,6 +26,18 @@ int dwmac_dma_reset(void __iomem *ioaddr) 10000, 200000); } +void dwmac_dma_clean(void __iomem *ioaddr) +{ + /* Clean the basic DMA registers up */ + writel(0, ioaddr + DMA_INTR_ENA); + writel(0x00020100, ioaddr + DMA_BUS_MODE); + writel(0, ioaddr + DMA_RCV_BASE_ADDR); + writel(0, ioaddr + DMA_TX_BASE_ADDR); + writel(0x00100000, ioaddr + DMA_CONTROL); + writel(0x00110001, ioaddr + DMA_AXI_BUS_MODE); + writel(0x0001FFFF, ioaddr + DMA_STATUS); +} + /* CSR1 enables the transmit DMA to check for new descriptor */ void dwmac_enable_dma_transmission(void __iomem *ioaddr) { diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 3f5eed8333a5..dea5a4d17677 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -169,6 +169,7 @@ struct dma_features; struct stmmac_dma_ops { /* DMA core initialization */ int (*reset)(void __iomem *ioaddr); + void (*clean)(void __iomem *ioaddr); void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg, int atds); void (*init_chan)(void __iomem *ioaddr, @@ -219,6 +220,8 @@ struct stmmac_dma_ops { #define stmmac_reset(__priv, __args...) \ stmmac_do_callback(__priv, dma, reset, __args) +#define stmmac_dma_clean(__priv, __args...) \ + stmmac_do_void_callback(__priv, dma, clean, __args) #define stmmac_dma_init(__priv, __args...) \ stmmac_do_void_callback(__priv, dma, init, __args) #define stmmac_init_chan(__priv, __args...) \ From patchwork Mon Feb 8 14:08:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379923 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=unavailable 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 120E3C433E0 for ; Mon, 8 Feb 2021 14:21:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D4A2E64E6C for ; Mon, 8 Feb 2021 14:21:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233056AbhBHOVi (ORCPT ); Mon, 8 Feb 2021 09:21:38 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57756 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232049AbhBHOKI (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 05/16] net: stmmac: Introduce MAC IRQs enable/disable methods Date: Mon, 8 Feb 2021 17:08:09 +0300 Message-ID: <20210208140820.10410-6-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: netdev@vger.kernel.org By design the DW MAC IRQ lane is shared between orthogonal IP-core functionality like MAC, DMA/MTL, MMC, SMA/MDIO, Safety, GPIOs, etc. These IRQs can be independently enabled/disabled by means of the corresponding IRQ enable/mask registers. In order to have a more flexible way of the device configuration let's introduce dedicated MAC core IRQs enable/disable interface methods for each IP-core the driver supports. It will be useful to have the MAC core IRQs enabled/disabled while the network device is being opened/closed respectively so to be able to handle the independent IRQs like GPIOs signaled via the same lane even while the device is released. The methods responsible for the MAC IRQs (de-)activating are added to the generic IRQs enable/disable functions. The later ones will be filled in the following commits with the rest of the interrupts control switchers and will be used to mask/unmask all the device IRQs while the network device is closed and unused. Note the main IRQ signal needs to be masked while the IRQs enable/disable procedure is in progress, because the IRQs handlers can also read/write the interrupts mask/enable/status registers. This modification is required for the case of the IRQs handler being setup at the device probe stage, which will be introduced later in one of the following up commits. Signed-off-by: Serge Semin --- .../ethernet/stmicro/stmmac/dwmac1000_core.c | 28 +++++++++---- .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 32 +++++++++++---- .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 15 ++++++- drivers/net/ethernet/stmicro/stmmac/hwif.h | 7 ++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 40 +++++++++++++++++++ 5 files changed, 105 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 2af4c8ac6fb7..7dc8b254c15a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -95,14 +95,6 @@ static void dwmac1000_core_init(struct mac_device_info *hw, writel(value, ioaddr + GMAC_CONTROL); - /* Mask GMAC interrupts */ - value = GMAC_INT_DEFAULT_MASK; - - if (hw->pcs) - value &= ~GMAC_INT_DISABLE_PCS; - - writel(value, ioaddr + GMAC_INT_MASK); - #ifdef STMMAC_VLAN_TAG_USED /* Tag detection without filtering */ writel(0x0, ioaddr + GMAC_VLAN_TAG); @@ -302,6 +294,24 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) writel(pmt, ioaddr + GMAC_PMT); } +static void dwmac1000_enable_mac_irq(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value = GMAC_INT_DEFAULT_MASK; + + if (hw->pcs) + value &= ~GMAC_INT_DISABLE_PCS; + + writel(value, ioaddr + GMAC_INT_MASK); +} + +static void dwmac1000_disable_mac_irq(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + + writel(0x7FF, ioaddr + GMAC_INT_MASK); +} + /* RGMII or SMII interface */ static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x) { @@ -548,6 +558,8 @@ const struct stmmac_ops dwmac1000_ops = { .set_mac = stmmac_set_mac, .rx_ipc = dwmac1000_rx_ipc_enable, .dump_regs = dwmac1000_dump_regs, + .enable_mac_irq = dwmac1000_enable_mac_irq, + .disable_mac_irq = dwmac1000_disable_mac_irq, .host_irq_status = dwmac1000_irq_status, .set_filter = dwmac1000_set_filter, .flow_ctrl = dwmac1000_flow_ctrl, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 29f765a246a0..8fc8d3cd238d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -46,14 +46,6 @@ static void dwmac4_core_init(struct mac_device_info *hw, } writel(value, ioaddr + GMAC_CONFIG); - - /* Enable GMAC interrupts */ - value = GMAC_INT_DEFAULT_ENABLE; - - if (hw->pcs) - value |= GMAC_PCS_IRQ_DEFAULT; - - writel(value, ioaddr + GMAC_INT_EN); } static void dwmac4_rx_queue_enable(struct mac_device_info *hw, @@ -777,6 +769,24 @@ static void dwmac4_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv) dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv); } +static void dwmac4_enable_mac_irq(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value = GMAC_INT_DEFAULT_ENABLE; + + if (hw->pcs) + value |= GMAC_PCS_IRQ_DEFAULT; + + writel(value, ioaddr + GMAC_INT_EN); +} + +static void dwmac4_disable_mac_irq(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + + writel(0, ioaddr + GMAC_INT_EN); +} + /* RGMII or SMII interface */ static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x) { @@ -1177,6 +1187,8 @@ const struct stmmac_ops dwmac4_ops = { .map_mtl_to_dma = dwmac4_map_mtl_dma, .config_cbs = dwmac4_config_cbs, .dump_regs = dwmac4_dump_regs, + .enable_mac_irq = dwmac4_enable_mac_irq, + .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, @@ -1219,6 +1231,8 @@ const struct stmmac_ops dwmac410_ops = { .map_mtl_to_dma = dwmac4_map_mtl_dma, .config_cbs = dwmac4_config_cbs, .dump_regs = dwmac4_dump_regs, + .enable_mac_irq = dwmac4_enable_mac_irq, + .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, @@ -1264,6 +1278,8 @@ const struct stmmac_ops dwmac510_ops = { .map_mtl_to_dma = dwmac4_map_mtl_dma, .config_cbs = dwmac4_config_cbs, .dump_regs = dwmac4_dump_regs, + .enable_mac_irq = dwmac4_enable_mac_irq, + .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index ad4df9bddcf3..12af0f831510 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -44,7 +44,6 @@ static void dwxgmac2_core_init(struct mac_device_info *hw, writel(tx, ioaddr + XGMAC_TX_CONFIG); writel(rx, ioaddr + XGMAC_RX_CONFIG); - writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); } static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable) @@ -239,6 +238,16 @@ static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space) reg_space[i] = readl(ioaddr + i * 4); } +static void dwxgmac2_enable_mac_irq(struct mac_device_info *hw) +{ + writel(XGMAC_INT_DEFAULT_EN, hw->pcsr + XGMAC_INT_EN); +} + +static void dwxgmac2_disable_mac_irq(struct mac_device_info *hw) +{ + writel(0, hw->pcsr + XGMAC_INT_EN); +} + static int dwxgmac2_host_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { @@ -1464,6 +1473,8 @@ const struct stmmac_ops dwxgmac210_ops = { .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, .config_cbs = dwxgmac2_config_cbs, .dump_regs = dwxgmac2_dump_regs, + .enable_mac_irq = dwxgmac2_enable_mac_irq, + .disable_mac_irq = dwxgmac2_disable_mac_irq, .host_irq_status = dwxgmac2_host_irq_status, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, .flow_ctrl = dwxgmac2_flow_ctrl, @@ -1525,6 +1536,8 @@ const struct stmmac_ops dwxlgmac2_ops = { .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, .config_cbs = dwxgmac2_config_cbs, .dump_regs = dwxgmac2_dump_regs, + .enable_mac_irq = dwxgmac2_enable_mac_irq, + .disable_mac_irq = dwxgmac2_disable_mac_irq, .host_irq_status = dwxgmac2_host_irq_status, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, .flow_ctrl = dwxgmac2_flow_ctrl, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index dea5a4d17677..68496b7a640b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -322,6 +322,9 @@ struct stmmac_ops { u32 queue); /* Dump MAC registers */ void (*dump_regs)(struct mac_device_info *hw, u32 *reg_space); + /* Enable/Disable MAC core interrupts */ + void (*enable_mac_irq)(struct mac_device_info *hw); + void (*disable_mac_irq)(struct mac_device_info *hw); /* Handle extra events on specific interrupts hw dependent */ int (*host_irq_status)(struct mac_device_info *hw, struct stmmac_extra_stats *x); @@ -429,6 +432,10 @@ struct stmmac_ops { stmmac_do_void_callback(__priv, mac, config_cbs, __args) #define stmmac_dump_mac_regs(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, dump_regs, __args) +#define stmmac_enable_mac_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, enable_mac_irq, __args) +#define stmmac_disable_mac_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, disable_mac_irq, __args) #define stmmac_host_irq_status(__priv, __args...) \ stmmac_do_callback(__priv, mac, host_irq_status, __args) #define stmmac_host_mtl_irq_status(__priv, __args...) \ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f70cab9f46d9..d124cbaceafd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -101,6 +101,8 @@ static unsigned int chain_mode; module_param(chain_mode, int, 0444); MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode"); +static void stmmac_enable_irq(struct stmmac_priv *priv); +static void stmmac_disable_irq(struct stmmac_priv *priv); static irqreturn_t stmmac_interrupt(int irq, void *dev_id); #ifdef CONFIG_DEBUG_FS @@ -2782,6 +2784,9 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) netif_set_real_num_rx_queues(dev, priv->plat->rx_queues_to_use); netif_set_real_num_tx_queues(dev, priv->plat->tx_queues_to_use); + /* Enable MAC/MTL/DMA/etc IRQs */ + stmmac_enable_irq(priv); + /* Start the ball rolling... */ stmmac_start_all_dma(priv); @@ -2794,6 +2799,8 @@ static void stmmac_hw_teardown(struct net_device *dev) stmmac_stop_all_dma(priv); + stmmac_disable_irq(priv); + stmmac_release_ptp(priv); stmmac_mac_set(priv, priv->ioaddr, false); @@ -4113,6 +4120,39 @@ static int stmmac_set_features(struct net_device *netdev, return 0; } +/** + * stmmac_enable_irq - device IRQs enable procedure + * @priv: driver private structure + * Description : enable all DW *MAC networking IRQs handled then in the + * main ISR. + */ +static void stmmac_enable_irq(struct stmmac_priv *priv) +{ + /* The main IRQ signal needs to be masked while the IRQs enable/disable + * procedure is in progress, because the individual IRQs handlers can + * also read/write the IRQs control registers. + */ + disable_irq(priv->dev->irq); + + stmmac_enable_mac_irq(priv, priv->hw); + + enable_irq(priv->dev->irq); +} + +/** + * stmmac_disable_irq - device IRQs disable procedure + * @priv: driver private structure + * Description : disable all DW *MAC networking IRQs. + */ +static void stmmac_disable_irq(struct stmmac_priv *priv) +{ + disable_irq(priv->dev->irq); + + stmmac_disable_mac_irq(priv, priv->hw); + + enable_irq(priv->dev->irq); +} + /** * stmmac_interrupt - main ISR * @irq: interrupt number. From patchwork Mon Feb 8 14:08:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 378975 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=unavailable 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 C45EFC433E0 for ; Mon, 8 Feb 2021 14:22:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 69FD364E75 for ; Mon, 8 Feb 2021 14:22:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232691AbhBHOVy (ORCPT ); Mon, 8 Feb 2021 09:21:54 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57758 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231579AbhBHOKG (ORCPT ); Mon, 8 Feb 2021 09:10:06 -0500 From: Serge Semin To: Rob Herring , Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S. Miller" , Jakub Kicinski , Maxime Ripard , Chen-Yu Tsai , Jernej Skrabec , Maxime Coquelin CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Vyacheslav Mitrofanov , , , , , Subject: [PATCH 06/16] net: stmmac: Extend DMA IRQs enable/disable interface Date: Mon, 8 Feb 2021 17:08:10 +0300 Message-ID: <20210208140820.10410-7-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: netdev@vger.kernel.org Similarly to the MAC core IRQs we need to be able to enable/disable all the DMA-related interrupts by means of the dedicated methods so the DMA IRQs would be enabled only when they are needed to be enabled (for instance while the network device being opened) and disabled otherwise. For that sake and for the sake of unification let's convert the currently available enable_dma_irq/disable_dma_irq callbacks to fully switching the DMA IRQs on/off and add the dedicated methods to toggle the DMA Tx/Rx IRQs when it's required. Note DMA channels initialization procedure won't enable the DMA IRQs anymore. Such modification won't break the DMA-related code because the default macro has both Tx and Rx DMA IRQs flags set anyway. So in order to make things working as usual we just need to call the stmmac_enable_dma_irq() method aside with the generic IRQs activating function. Signed-off-by: Serge Semin --- Note folks, in the framework of this commit we've naturally fixed an invalid default DMA IRQs enable macro usage for the DW MAC v4.10 DMA initialization. I don't really know why it hasn't been noticed so far especially seeing the 4.x Normal/Abnormal IRQs bit fields have been used to enable these IRQs on 4.10a hardware. I leave this commit as is for now. But if tests prove the bug-fix actuality, then most likely we'll need to create a dedicated patch to correctly have it backported. --- .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 33 ++++++++---- .../ethernet/stmicro/stmmac/dwmac1000_dma.c | 5 +- .../ethernet/stmicro/stmmac/dwmac100_dma.c | 5 +- .../net/ethernet/stmicro/stmmac/dwmac4_dma.c | 10 ++-- .../net/ethernet/stmicro/stmmac/dwmac4_dma.h | 11 ++-- .../net/ethernet/stmicro/stmmac/dwmac4_lib.c | 51 ++++++++++++------- .../net/ethernet/stmicro/stmmac/dwmac_dma.h | 6 ++- .../net/ethernet/stmicro/stmmac/dwmac_lib.c | 26 +++++++--- .../ethernet/stmicro/stmmac/dwxgmac2_dma.c | 31 +++++++---- drivers/net/ethernet/stmicro/stmmac/hwif.h | 12 +++-- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 26 ++++++++-- 11 files changed, 142 insertions(+), 74 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index a5e0eff4a387..35d1aeb20fa9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -285,7 +285,6 @@ static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) static void sun8i_dwmac_dma_init(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg, int atds) { - writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); } @@ -337,32 +336,42 @@ static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, } } -static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, - bool rx, bool tx) +static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); +} + +static void sun8i_dwmac_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, + bool on) { u32 value = readl(ioaddr + EMAC_INT_EN); - if (rx) + if (on) value |= EMAC_RX_INT; - if (tx) - value |= EMAC_TX_INT; + else + value &= ~EMAC_RX_INT; writel(value, ioaddr + EMAC_INT_EN); } -static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, - bool rx, bool tx) +static void sun8i_dwmac_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, + bool on) { u32 value = readl(ioaddr + EMAC_INT_EN); - if (rx) - value &= ~EMAC_RX_INT; - if (tx) + if (on) + value |= EMAC_TX_INT; + else value &= ~EMAC_TX_INT; writel(value, ioaddr + EMAC_INT_EN); } +static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + EMAC_INT_EN); +} + static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) { u32 v; @@ -533,6 +542,8 @@ static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { .dma_tx_mode = sun8i_dwmac_dma_operation_mode_tx, .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, .enable_dma_irq = sun8i_dwmac_enable_dma_irq, + .switch_dma_rx_irq = sun8i_dwmac_switch_dma_rx_irq, + .switch_dma_tx_irq = sun8i_dwmac_switch_dma_tx_irq, .disable_dma_irq = sun8i_dwmac_disable_dma_irq, .start_tx = sun8i_dwmac_dma_start_tx, .stop_tx = sun8i_dwmac_dma_stop_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index bae63e1420f2..c1b79f712323 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -105,9 +105,6 @@ static void dwmac1000_dma_init(void __iomem *ioaddr, value |= DMA_BUS_MODE_AAL; writel(value, ioaddr + DMA_BUS_MODE); - - /* Mask interrupts by writing to CSR7 */ - writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); } static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz) @@ -256,6 +253,8 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = { .dma_tx_mode = dwmac1000_dma_operation_mode_tx, .enable_dma_transmission = dwmac_enable_dma_transmission, .enable_dma_irq = dwmac_enable_dma_irq, + .switch_dma_rx_irq = dwmac_switch_dma_rx_irq, + .switch_dma_tx_irq = dwmac_switch_dma_tx_irq, .disable_dma_irq = dwmac_disable_dma_irq, .start_tx = dwmac_dma_start_tx, .stop_tx = dwmac_dma_stop_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c index ad51a7949a42..e880c07dd34c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c @@ -24,9 +24,6 @@ static void dwmac100_dma_init(void __iomem *ioaddr, /* Enable Application Access by writing to DMA CSR0 */ writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT), ioaddr + DMA_BUS_MODE); - - /* Mask interrupts by writing to CSR7 */ - writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); } /* Store and Forward capability is not used at all. @@ -102,6 +99,8 @@ const struct stmmac_dma_ops dwmac100_dma_ops = { .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr, .enable_dma_transmission = dwmac_enable_dma_transmission, .enable_dma_irq = dwmac_enable_dma_irq, + .switch_dma_rx_irq = dwmac_switch_dma_rx_irq, + .switch_dma_tx_irq = dwmac_switch_dma_tx_irq, .disable_dma_irq = dwmac_disable_dma_irq, .start_tx = dwmac_dma_start_tx, .stop_tx = dwmac_dma_stop_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 59da9ff36a43..924abda6c131 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -118,10 +118,6 @@ static void dwmac4_dma_init_channel(void __iomem *ioaddr, if (dma_cfg->pblx8) value = value | DMA_BUS_MODE_PBL; writel(value, ioaddr + DMA_CHAN_CONTROL(chan)); - - /* Mask interrupts by writing to CSR7 */ - writel(DMA_CHAN_INTR_DEFAULT_MASK, - ioaddr + DMA_CHAN_INTR_ENA(chan)); } static void dwmac4_dma_init(void __iomem *ioaddr, @@ -502,6 +498,8 @@ const struct stmmac_dma_ops dwmac4_dma_ops = { .dma_rx_mode = dwmac4_dma_rx_chan_op_mode, .dma_tx_mode = dwmac4_dma_tx_chan_op_mode, .enable_dma_irq = dwmac4_enable_dma_irq, + .switch_dma_rx_irq = dwmac4_switch_dma_rx_irq, + .switch_dma_tx_irq = dwmac4_switch_dma_tx_irq, .disable_dma_irq = dwmac4_disable_dma_irq, .start_tx = dwmac4_dma_start_tx, .stop_tx = dwmac4_dma_stop_tx, @@ -531,7 +529,9 @@ const struct stmmac_dma_ops dwmac410_dma_ops = { .dma_rx_mode = dwmac4_dma_rx_chan_op_mode, .dma_tx_mode = dwmac4_dma_tx_chan_op_mode, .enable_dma_irq = dwmac410_enable_dma_irq, - .disable_dma_irq = dwmac410_disable_dma_irq, + .switch_dma_rx_irq = dwmac410_switch_dma_rx_irq, + .switch_dma_tx_irq = dwmac410_switch_dma_tx_irq, + .disable_dma_irq = dwmac4_disable_dma_irq, .start_tx = dwmac4_dma_start_tx, .stop_tx = dwmac4_dma_stop_tx, .start_rx = dwmac4_dma_start_rx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index 8391ca63d943..d8c9f9107879 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -197,10 +197,13 @@ #define DMA_CHAN0_DBG_STAT_RPS_SHIFT 8 int dwmac4_dma_reset(void __iomem *ioaddr); -void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); -void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); -void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); -void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); +void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan); +void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan); +void dwmac4_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac410_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac4_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac410_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan); void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan); void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan); void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c index 0b4ee2dbb691..ee46eabf11af 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -90,54 +90,69 @@ void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan) writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan)); } -void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan)); +} + +void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10, ioaddr + DMA_CHAN_INTR_ENA(chan)); +} + +void dwmac4_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan)); - if (rx) + if (on) value |= DMA_CHAN_INTR_DEFAULT_RX; - if (tx) - value |= DMA_CHAN_INTR_DEFAULT_TX; + else + value &= ~DMA_CHAN_INTR_DEFAULT_RX; writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan)); } -void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac4_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan)); - if (rx) - value |= DMA_CHAN_INTR_DEFAULT_RX_4_10; - if (tx) - value |= DMA_CHAN_INTR_DEFAULT_TX_4_10; + if (on) + value |= DMA_CHAN_INTR_DEFAULT_TX; + else + value &= ~DMA_CHAN_INTR_DEFAULT_TX; writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan)); } -void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac410_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan)); - if (rx) - value &= ~DMA_CHAN_INTR_DEFAULT_RX; - if (tx) - value &= ~DMA_CHAN_INTR_DEFAULT_TX; + if (on) + value |= DMA_CHAN_INTR_DEFAULT_RX_4_10; + else + value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10; writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan)); } -void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac410_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan)); - if (rx) - value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10; - if (tx) + if (on) + value |= DMA_CHAN_INTR_DEFAULT_TX_4_10; + else value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10; writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan)); } +void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + DMA_CHAN_INTR_ENA(chan)); +} + int dwmac4_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x, u32 chan) { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index f6e759d039d7..a692ed714426 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -132,8 +132,10 @@ #define NUM_DWMAC1000_DMA_REGS 23 void dwmac_enable_dma_transmission(void __iomem *ioaddr); -void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); -void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx); +void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan); +void dwmac_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on); +void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan); void dwmac_dma_init_tx(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg, dma_addr_t dma_tx_phy, u32 chan); void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 2186e95d5aa4..0ba986be83f5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -44,30 +44,40 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr) writel(1, ioaddr + DMA_XMT_POLL_DEMAND); } -void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); +} + +void dwmac_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_INTR_ENA); - if (rx) + if (on) value |= DMA_INTR_DEFAULT_RX; - if (tx) - value |= DMA_INTR_DEFAULT_TX; + else + value &= ~DMA_INTR_DEFAULT_RX; writel(value, ioaddr + DMA_INTR_ENA); } -void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx) +void dwmac_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + DMA_INTR_ENA); - if (rx) - value &= ~DMA_INTR_DEFAULT_RX; - if (tx) + if (on) + value |= DMA_INTR_DEFAULT_TX; + else value &= ~DMA_INTR_DEFAULT_TX; writel(value, ioaddr + DMA_INTR_ENA); } +void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + DMA_INTR_ENA); +} + void dwmac_dma_init_tx(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg, dma_addr_t dma_tx_phy, u32 chan) { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 77308c5c5d29..94f101d1df6c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -42,7 +42,6 @@ static void dwxgmac2_dma_init_chan(void __iomem *ioaddr, value |= XGMAC_PBLx8; writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan)); - writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); } static void dwxgmac2_dma_init_rx_chan(void __iomem *ioaddr, @@ -248,32 +247,40 @@ static void dwxgmac2_dma_tx_mode(void __iomem *ioaddr, int mode, writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); } -static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan, - bool rx, bool tx) +static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); +} + +static void dwxgmac2_switch_dma_rx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); - if (rx) + if (on) value |= XGMAC_DMA_INT_DEFAULT_RX; - if (tx) - value |= XGMAC_DMA_INT_DEFAULT_TX; + else + value &= ~XGMAC_DMA_INT_DEFAULT_RX; writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); } -static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan, - bool rx, bool tx) +static void dwxgmac2_switch_dma_tx_irq(void __iomem *ioaddr, u32 chan, bool on) { u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); - if (rx) - value &= ~XGMAC_DMA_INT_DEFAULT_RX; - if (tx) + if (on) + value |= XGMAC_DMA_INT_DEFAULT_TX; + else value &= ~XGMAC_DMA_INT_DEFAULT_TX; writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); } +static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); +} + static void dwxgmac2_dma_start_tx(void __iomem *ioaddr, u32 chan) { u32 value; @@ -557,6 +564,8 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = { .dma_rx_mode = dwxgmac2_dma_rx_mode, .dma_tx_mode = dwxgmac2_dma_tx_mode, .enable_dma_irq = dwxgmac2_enable_dma_irq, + .switch_dma_rx_irq = dwxgmac2_switch_dma_rx_irq, + .switch_dma_tx_irq = dwxgmac2_switch_dma_tx_irq, .disable_dma_irq = dwxgmac2_disable_dma_irq, .start_tx = dwxgmac2_dma_start_tx, .stop_tx = dwxgmac2_dma_stop_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 68496b7a640b..6412c969cbb7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -192,10 +192,10 @@ struct stmmac_dma_ops { void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, void __iomem *ioaddr); void (*enable_dma_transmission) (void __iomem *ioaddr); - void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan, - bool rx, bool tx); - void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan, - bool rx, bool tx); + void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan); + void (*switch_dma_rx_irq)(void __iomem *ioaddr, u32 chan, bool on); + void (*switch_dma_tx_irq)(void __iomem *ioaddr, u32 chan, bool on); + void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan); void (*start_tx)(void __iomem *ioaddr, u32 chan); void (*stop_tx)(void __iomem *ioaddr, u32 chan); void (*start_rx)(void __iomem *ioaddr, u32 chan); @@ -244,6 +244,10 @@ struct stmmac_dma_ops { stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __args) #define stmmac_enable_dma_irq(__priv, __args...) \ stmmac_do_void_callback(__priv, dma, enable_dma_irq, __args) +#define stmmac_switch_dma_rx_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, dma, switch_dma_rx_irq, __args) +#define stmmac_switch_dma_tx_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, dma, switch_dma_tx_irq, __args) #define stmmac_disable_dma_irq(__priv, __args...) \ stmmac_do_void_callback(__priv, dma, disable_dma_irq, __args) #define stmmac_start_tx(__priv, __args...) \ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d124cbaceafd..3e6cc91f08c5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2199,7 +2199,7 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan) if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) { if (napi_schedule_prep(&ch->rx_napi)) { spin_lock_irqsave(&ch->lock, flags); - stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 0); + stmmac_switch_dma_rx_irq(priv, priv->ioaddr, chan, 0); spin_unlock_irqrestore(&ch->lock, flags); __napi_schedule(&ch->rx_napi); } @@ -2208,7 +2208,7 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan) if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) { if (napi_schedule_prep(&ch->tx_napi)) { spin_lock_irqsave(&ch->lock, flags); - stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1); + stmmac_switch_dma_tx_irq(priv, priv->ioaddr, chan, 0); spin_unlock_irqrestore(&ch->lock, flags); __napi_schedule(&ch->tx_napi); } @@ -2413,7 +2413,7 @@ static enum hrtimer_restart stmmac_tx_timer(struct hrtimer *t) unsigned long flags; spin_lock_irqsave(&ch->lock, flags); - stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, 0, 1); + stmmac_switch_dma_tx_irq(priv, priv->ioaddr, ch->index, 0); spin_unlock_irqrestore(&ch->lock, flags); __napi_schedule(&ch->tx_napi); } @@ -3963,7 +3963,7 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget) unsigned long flags; spin_lock_irqsave(&ch->lock, flags); - stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 0); + stmmac_switch_dma_rx_irq(priv, priv->ioaddr, chan, 1); spin_unlock_irqrestore(&ch->lock, flags); } @@ -3987,7 +3987,7 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget) unsigned long flags; spin_lock_irqsave(&ch->lock, flags); - stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 0, 1); + stmmac_switch_dma_tx_irq(priv, priv->ioaddr, chan, 1); spin_unlock_irqrestore(&ch->lock, flags); } @@ -4128,12 +4128,19 @@ static int stmmac_set_features(struct net_device *netdev, */ static void stmmac_enable_irq(struct stmmac_priv *priv) { + u32 chan, maxq; + /* The main IRQ signal needs to be masked while the IRQs enable/disable * procedure is in progress, because the individual IRQs handlers can * also read/write the IRQs control registers. */ disable_irq(priv->dev->irq); + maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); + + for (chan = 0; chan < maxq; ++chan) + stmmac_enable_dma_irq(priv, priv->ioaddr, chan); + stmmac_enable_mac_irq(priv, priv->hw); enable_irq(priv->dev->irq); @@ -4146,10 +4153,19 @@ static void stmmac_enable_irq(struct stmmac_priv *priv) */ static void stmmac_disable_irq(struct stmmac_priv *priv) { + u32 chan, maxq; + disable_irq(priv->dev->irq); stmmac_disable_mac_irq(priv, priv->hw); + maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); + + stmmac_disable_mac_irq(priv, priv->hw); + + for (chan = 0; chan < maxq; ++chan) + stmmac_disable_dma_irq(priv, priv->ioaddr, chan); + enable_irq(priv->dev->irq); } From patchwork Mon Feb 8 14:08:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379926 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=unavailable 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 386EEC433DB for ; Mon, 8 Feb 2021 14:18:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EAAFD64E60 for ; Mon, 8 Feb 2021 14:18:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231953AbhBHOSd (ORCPT ); Mon, 8 Feb 2021 09:18:33 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57514 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231563AbhBHOJl (ORCPT ); Mon, 8 Feb 2021 09:09:41 -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 07/16] net: stmmac: Introduce MTL IRQs enable/disable methods Date: Mon, 8 Feb 2021 17:08:11 +0300 Message-ID: <20210208140820.10410-8-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: netdev@vger.kernel.org Aside with the DMA and MAC IRQs enable/disable methods the MTL IRQs state regulation callbacks will be used to activate/de-activate the network-related IRQs while the DW MAC network device is opened, up and running/closed, down and stopped. Note the MTL IRQs are enabled for the Rx Queues only in the framework of the DMA operation mode configuration procedure as it has been done before this commit (stmmac_dma_operation_mode() method). But in future it may change that's why we need to have an additional "bool tx" argument. Moreover there is no point in preserving the MTL IRQs interrupts control register content for both DW MAC 4.x and DW xGMAC as it is related to the MTL IRQs enable/disable configs only, which are tuned by the provided methods and aren't touched by any other function. Thus we disable the rest of the unsupported IRQs so not to confuse the MTL IRQs status handler. Also note there is no need in enabling the MTL IRQs in the stmmac_set_dma_operation_mode() method, because the later is called from the DMA IRQ context and doesn't really intent the MTL IRQs setup change anyway. Signed-off-by: Serge Semin --- .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 23 +++++++++++++++++++ .../net/ethernet/stmicro/stmmac/dwmac4_dma.c | 7 +----- .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 21 +++++++++++++++++ .../ethernet/stmicro/stmmac/dwxgmac2_dma.c | 4 ---- drivers/net/ethernet/stmicro/stmmac/hwif.h | 8 +++++++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 14 +++++++++-- 6 files changed, 65 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 8fc8d3cd238d..9ad48a0f96a6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -820,6 +820,23 @@ static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x) } } +static void dwmac4_enable_mtl_irq(void __iomem *ioaddr, u32 chan, + bool rx, bool tx) +{ + u32 value = 0; + + /* Enable just MTL RX overflow IRQ for now */ + if (rx) + value |= MTL_RX_OVERFLOW_INT_EN; + + writel(value, ioaddr + MTL_CHAN_INT_CTRL(chan)); +} + +static void dwmac4_disable_mtl_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + MTL_CHAN_INT_CTRL(chan)); +} + static int dwmac4_irq_mtl_status(struct mac_device_info *hw, u32 chan) { void __iomem *ioaddr = hw->pcsr; @@ -1190,6 +1207,8 @@ const struct stmmac_ops dwmac4_ops = { .enable_mac_irq = dwmac4_enable_mac_irq, .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, + .enable_mtl_irq = dwmac4_enable_mtl_irq, + .disable_mtl_irq = dwmac4_disable_mtl_irq, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, .pmt = dwmac4_pmt, @@ -1234,6 +1253,8 @@ const struct stmmac_ops dwmac410_ops = { .enable_mac_irq = dwmac4_enable_mac_irq, .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, + .enable_mtl_irq = dwmac4_enable_mtl_irq, + .disable_mtl_irq = dwmac4_disable_mtl_irq, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, .pmt = dwmac4_pmt, @@ -1281,6 +1302,8 @@ const struct stmmac_ops dwmac510_ops = { .enable_mac_irq = dwmac4_enable_mac_irq, .disable_mac_irq = dwmac4_disable_mac_irq, .host_irq_status = dwmac4_irq_status, + .enable_mtl_irq = dwmac4_enable_mtl_irq, + .disable_mtl_irq = dwmac4_disable_mtl_irq, .host_mtl_irq_status = dwmac4_irq_mtl_status, .flow_ctrl = dwmac4_flow_ctrl, .pmt = dwmac4_pmt, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 924abda6c131..11bf0167e438 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -201,7 +201,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, u32 channel, int fifosz, u8 qmode) { unsigned int rqs = fifosz / 256 - 1; - u32 mtl_rx_op, mtl_rx_int; + u32 mtl_rx_op; mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel)); @@ -262,11 +262,6 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, } writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel)); - - /* Enable MTL RX overflow */ - mtl_rx_int = readl(ioaddr + MTL_CHAN_INT_CTRL(channel)); - writel(mtl_rx_int | MTL_RX_OVERFLOW_INT_EN, - ioaddr + MTL_CHAN_INT_CTRL(channel)); } static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 12af0f831510..3a93e1b10d2e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -285,6 +285,23 @@ static int dwxgmac2_host_irq_status(struct mac_device_info *hw, return ret; } +static void dwxgmac2_enable_mtl_irq(void __iomem *ioaddr, u32 chan, + bool rx, bool tx) +{ + u32 value = 0; + + /* Enable just MTL RX overflow IRQ for now */ + if (rx) + value |= XGMAC_RXOIE; + + writel(value, ioaddr + XGMAC_MTL_QINTEN(chan)); +} + +static void dwxgmac2_disable_mtl_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + XGMAC_MTL_QINTEN(chan)); +} + static int dwxgmac2_host_mtl_irq_status(struct mac_device_info *hw, u32 chan) { void __iomem *ioaddr = hw->pcsr; @@ -1476,6 +1493,8 @@ const struct stmmac_ops dwxgmac210_ops = { .enable_mac_irq = dwxgmac2_enable_mac_irq, .disable_mac_irq = dwxgmac2_disable_mac_irq, .host_irq_status = dwxgmac2_host_irq_status, + .enable_mtl_irq = dwxgmac2_enable_mtl_irq, + .disable_mtl_irq = dwxgmac2_disable_mtl_irq, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, .flow_ctrl = dwxgmac2_flow_ctrl, .pmt = dwxgmac2_pmt, @@ -1539,6 +1558,8 @@ const struct stmmac_ops dwxlgmac2_ops = { .enable_mac_irq = dwxgmac2_enable_mac_irq, .disable_mac_irq = dwxgmac2_disable_mac_irq, .host_irq_status = dwxgmac2_host_irq_status, + .enable_mtl_irq = dwxgmac2_enable_mtl_irq, + .disable_mtl_irq = dwxgmac2_disable_mtl_irq, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, .flow_ctrl = dwxgmac2_flow_ctrl, .pmt = dwxgmac2_pmt, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 94f101d1df6c..7812d00e7637 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -198,10 +198,6 @@ static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode, } writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); - - /* Enable MTL RX overflow */ - value = readl(ioaddr + XGMAC_MTL_QINTEN(channel)); - writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel)); } static void dwxgmac2_dma_tx_mode(void __iomem *ioaddr, int mode, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 6412c969cbb7..b933347cd991 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -332,6 +332,10 @@ struct stmmac_ops { /* Handle extra events on specific interrupts hw dependent */ int (*host_irq_status)(struct mac_device_info *hw, struct stmmac_extra_stats *x); + /* Enable/Disable MTL interrupts */ + void (*enable_mtl_irq)(void __iomem *ioaddr, u32 chan, + bool rx, bool tx); + void (*disable_mtl_irq)(void __iomem *ioaddr, u32 chan); /* Handle MTL interrupts */ int (*host_mtl_irq_status)(struct mac_device_info *hw, u32 chan); /* Multicast filter setting */ @@ -442,6 +446,10 @@ struct stmmac_ops { stmmac_do_void_callback(__priv, mac, disable_mac_irq, __args) #define stmmac_host_irq_status(__priv, __args...) \ stmmac_do_callback(__priv, mac, host_irq_status, __args) +#define stmmac_enable_mtl_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, enable_mtl_irq, __args) +#define stmmac_disable_mtl_irq(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, disable_mtl_irq, __args) #define stmmac_host_mtl_irq_status(__priv, __args...) \ stmmac_do_callback(__priv, mac, host_mtl_irq_status, __args) #define stmmac_set_filter(__priv, __args...) \ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3e6cc91f08c5..33065195c499 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4129,6 +4129,7 @@ static int stmmac_set_features(struct net_device *netdev, static void stmmac_enable_irq(struct stmmac_priv *priv) { u32 chan, maxq; + bool rx, tx; /* The main IRQ signal needs to be masked while the IRQs enable/disable * procedure is in progress, because the individual IRQs handlers can @@ -4138,9 +4139,15 @@ static void stmmac_enable_irq(struct stmmac_priv *priv) maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); - for (chan = 0; chan < maxq; ++chan) + for (chan = 0; chan < maxq; ++chan) { stmmac_enable_dma_irq(priv, priv->ioaddr, chan); + rx = (chan < priv->plat->rx_queues_to_use); + tx = (chan < priv->plat->tx_queues_to_use); + + stmmac_enable_mtl_irq(priv, priv->ioaddr, chan, rx, tx); + } + stmmac_enable_mac_irq(priv, priv->hw); enable_irq(priv->dev->irq); @@ -4163,8 +4170,11 @@ static void stmmac_disable_irq(struct stmmac_priv *priv) stmmac_disable_mac_irq(priv, priv->hw); - for (chan = 0; chan < maxq; ++chan) + for (chan = 0; chan < maxq; ++chan) { + stmmac_disable_mtl_irq(priv, priv->ioaddr, chan); + stmmac_disable_dma_irq(priv, priv->ioaddr, chan); + } enable_irq(priv->dev->irq); } 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: 378973 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=unavailable 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 63E65C43381 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 35A9164EA1 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232992AbhBHOWz (ORCPT ); Mon, 8 Feb 2021 09:22:55 -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: netdev@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: 378977 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=unavailable 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 C4123C433E0 for ; Mon, 8 Feb 2021 14:20:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7F3AA64E30 for ; Mon, 8 Feb 2021 14:20:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232802AbhBHOUM (ORCPT ); Mon, 8 Feb 2021 09:20:12 -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: netdev@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: 379922 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=unavailable 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 EC643C433E0 for ; Mon, 8 Feb 2021 14:23:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 82E5F64E2E for ; Mon, 8 Feb 2021 14:23:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232835AbhBHOWS (ORCPT ); Mon, 8 Feb 2021 09:22:18 -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: netdev@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: 379925 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=unavailable 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 A758DC433E0 for ; Mon, 8 Feb 2021 14:20:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5EBBB64E2E for ; Mon, 8 Feb 2021 14:20:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231132AbhBHOT2 (ORCPT ); Mon, 8 Feb 2021 09:19:28 -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: netdev@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: 378974 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=unavailable 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 2EF12C433E6 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E33A264E8A for ; Mon, 8 Feb 2021 14:23:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232820AbhBHOWt (ORCPT ); Mon, 8 Feb 2021 09:22:49 -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: netdev@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:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379924 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=unavailable 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 350A1C433DB for ; Mon, 8 Feb 2021 14:21:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E265E64E60 for ; Mon, 8 Feb 2021 14:21:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232401AbhBHOUe (ORCPT ); Mon, 8 Feb 2021 09:20:34 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57516 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231756AbhBHOJr (ORCPT ); Mon, 8 Feb 2021 09:09:47 -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 13/16] net: stmmac: Request IRQs at device probe stage Date: Mon, 8 Feb 2021 17:08:17 +0300 Message-ID: <20210208140820.10410-14-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: netdev@vger.kernel.org Normally all DW *MAC IRQs are signalled by a single lane called sbd_intr_o. It is used to raise MAC, DMA, MMC, PMT, GPIO, etc interrupts. Most of those IRQs are connected with the networking activity of the controller, so it's ok to have the IRQs setup only while the network is up and running. But DW MAC GPIOs in general act as an independent signalling interface, so its interrupts must be handled no matter whether the NIC is configured or not. In that case the IRQs must be configured on the probe stage (before DW MAC GPIO chip is registered), which has been provided in the framework of this commit. This modification requires a more careful work with the DW MAC network- related interrupts. They have to be enabled only while the network interface is opened, and disabled otherwise. Moreover since the interrupts can be raised by some unrelated source via GPIs, which could be also marked as system-wake capable, PMT/WoL events are allowed to be forwarded to the PM-subsystem only when the STMMAC_UP flag is set. Note by moving the IRQs setup procedure to the probe method we not only make the code cleaner but also speed up the network interface initialization/de-initialization process. Signed-off-by: Serge Semin --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 157 +++++++++++------- 1 file changed, 96 insertions(+), 61 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c4c41b554c6a..d75c851721f7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2810,9 +2810,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) netif_set_real_num_rx_queues(dev, priv->plat->rx_queues_to_use); netif_set_real_num_tx_queues(dev, priv->plat->tx_queues_to_use); - /* Enable MAC/MTL/DMA/etc IRQs */ - stmmac_enable_irq(priv); - /* Start the ball rolling... */ stmmac_start_all_dma(priv); @@ -2825,8 +2822,6 @@ static void stmmac_hw_teardown(struct net_device *dev) stmmac_stop_all_dma(priv); - stmmac_disable_irq(priv); - stmmac_release_ptp(priv); stmmac_mac_set(priv, priv->ioaddr, false); @@ -2929,57 +2924,13 @@ static int stmmac_open(struct net_device *dev) /* We may have called phylink_speed_down before */ phylink_speed_up(priv->phylink); - /* Request the IRQ lines */ - ret = request_irq(dev->irq, stmmac_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(ret < 0)) { - netdev_err(priv->dev, - "%s: ERROR: allocating the IRQ %d (error: %d)\n", - __func__, dev->irq, ret); - goto irq_error; - } - - /* Request the Wake IRQ in case of another line is used for WoL */ - if (priv->wol_irq != dev->irq) { - ret = request_irq(priv->wol_irq, stmmac_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(ret < 0)) { - netdev_err(priv->dev, - "%s: ERROR: allocating the WoL IRQ %d (%d)\n", - __func__, priv->wol_irq, ret); - goto wolirq_error; - } - } - - /* Request the IRQ lines */ - if (priv->lpi_irq > 0) { - ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED, - dev->name, dev); - if (unlikely(ret < 0)) { - netdev_err(priv->dev, - "%s: ERROR: allocating the LPI IRQ %d (%d)\n", - __func__, priv->lpi_irq, ret); - goto lpiirq_error; - } - } + stmmac_enable_irq(priv); stmmac_enable_all_queues(priv); netif_tx_start_all_queues(priv->dev); return 0; -lpiirq_error: - if (priv->wol_irq != dev->irq) - free_irq(priv->wol_irq, dev); -wolirq_error: - free_irq(dev->irq, dev); -irq_error: - phylink_stop(priv->phylink); - - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) - hrtimer_cancel(&priv->tx_queue[chan].txtimer); - - stmmac_hw_teardown(dev); init_error: free_dma_desc_resources(priv); dma_desc_error: @@ -3009,12 +2960,8 @@ static int stmmac_release(struct net_device *dev) for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) hrtimer_cancel(&priv->tx_queue[chan].txtimer); - /* Free the IRQ lines */ - free_irq(dev->irq, dev); - if (priv->wol_irq != dev->irq) - free_irq(priv->wol_irq, dev); - if (priv->lpi_irq > 0) - free_irq(priv->lpi_irq, dev); + /* Disable the network IRQs */ + stmmac_disable_irq(priv); if (priv->eee_enabled) { priv->tx_path_in_lpi_mode = false; @@ -4252,19 +4199,21 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) u32 queue; bool xmac; - xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; - queues_count = (rx_cnt > tx_cnt) ? rx_cnt : tx_cnt; + /* Check if adapter is up */ + if (!stmmac_is_up(priv)) + return IRQ_HANDLED; + /* Wake up the system if PMT is available and has been enabled */ if (priv->irq_wake) pm_wakeup_event(priv->device, 0); - /* Check if adapter is up */ - if (!stmmac_is_up(priv)) - return IRQ_HANDLED; /* Check if a fatal error happened */ if (stmmac_safety_feat_interrupt(priv)) return IRQ_HANDLED; + xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; + queues_count = (rx_cnt > tx_cnt) ? rx_cnt : tx_cnt; + /* To handle GMAC own interrupts */ if ((priv->plat->has_gmac) || xmac) { int status = stmmac_host_irq_status(priv, priv->hw, &priv->xstats); @@ -4306,6 +4255,76 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * stmmac_request_irq - request DW MAC IRQs + * @priv: driver private structure + * Description : setup the ISR for all available interrupt signals. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int stmmac_request_irq(struct stmmac_priv *priv) +{ + struct net_device *dev = priv->dev; + int ret; + + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + return ret; + } + + if (priv->wol_irq != dev->irq) { + ret = request_irq(priv->wol_irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the WoL IRQ %d (%d)\n", + __func__, priv->wol_irq, ret); + goto wolirq_error; + } + } + + if (priv->lpi_irq > 0) { + ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED, + dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the LPI IRQ %d (%d)\n", + __func__, priv->lpi_irq, ret); + goto lpiirq_error; + } + } + + return 0; + +lpiirq_error: + if (priv->wol_irq != dev->irq) + free_irq(priv->wol_irq, dev); + +wolirq_error: + free_irq(dev->irq, dev); + + return ret; +} + +/** + * stmmac_request_irq - free DW MAC IRQs + * @priv: driver private structure + * Description : free the main/WoL/LPI IRQs. + */ +static void stmmac_free_irq(struct stmmac_priv *priv) +{ + free_irq(priv->dev->irq, priv->dev); + if (priv->wol_irq != priv->dev->irq) + free_irq(priv->wol_irq, priv->dev); + if (priv->lpi_irq > 0) + free_irq(priv->lpi_irq, priv->dev); +} + #ifdef CONFIG_NET_POLL_CONTROLLER /* Polling receive - used by NETCONSOLE and other diagnostic tools * to allow network I/O with interrupts disabled. @@ -4906,6 +4925,13 @@ static int stmmac_hw_init(struct stmmac_priv *priv) "Enable RX Mitigation via HW Watchdog Timer\n"); } + /* Disable all the device IRQs on HW initialization stage in case if + * the NIC has been used by another software before the kernel and + * the reset control capability isn't provided so further IRQs setup + * wouldn't end up with handling spurious interrupts. + */ + stmmac_disable_irq(priv); + return 0; } @@ -5190,6 +5216,10 @@ int stmmac_dvr_probe(struct device *device, stmmac_check_pcs_mode(priv); + ret = stmmac_request_irq(priv); + if (ret) + goto error_request_irq; + if (priv->hw->pcs != STMMAC_PCS_TBI && priv->hw->pcs != STMMAC_PCS_RTBI) { /* MDIO bus Registration */ @@ -5238,6 +5268,8 @@ int stmmac_dvr_probe(struct device *device, priv->hw->pcs != STMMAC_PCS_RTBI) stmmac_mdio_unregister(ndev); error_mdio_register: + stmmac_free_irq(priv); +error_request_irq: stmmac_napi_del(ndev); error_hw_init: destroy_workqueue(priv->wq); @@ -5274,6 +5306,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_free_irq(priv); reset_control_assert(priv->plat->stmmac_rst); destroy_workqueue(priv->wq); mutex_destroy(&priv->lock); @@ -5440,6 +5473,8 @@ int stmmac_resume(struct device *dev) stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw); + stmmac_enable_irq(priv); + stmmac_enable_all_queues(priv); mutex_unlock(&priv->lock); 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: 378972 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=unavailable 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 05636C43332 for ; Mon, 8 Feb 2021 14:23:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C6ED464E88 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233179AbhBHOXW (ORCPT ); Mon, 8 Feb 2021 09:23:22 -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: netdev@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 From patchwork Mon Feb 8 14:08:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379920 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=unavailable 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 BC252C4332E for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 869B964E88 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233141AbhBHOXI (ORCPT ); Mon, 8 Feb 2021 09:23:08 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57770 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232445AbhBHOKv (ORCPT ); Mon, 8 Feb 2021 09:10:51 -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 15/16] net: stmmac: Add DW GMAC GPIOs support Date: Mon, 8 Feb 2021 17:08:19 +0300 Message-ID: <20210208140820.10410-16-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: netdev@vger.kernel.org Synopsys DW GMAC can be synthesized with up to four GPIs and four GPOs support, which in case if enabled can be configured via a MAC CSR 0xe0. In order to have the DW GMAC GPIO interface supported in the STMMAC GPIO driver we just need to define the GPIO configs accessors and GPI state getter. Signed-off-by: Serge Semin --- Folks, I don't know whether the same GPIO CSR layout is defined for some other DW MAC IP-core. So for now the accessors have been created for GMACs only. But if you are sure the callbacks can be used for some other IP, I can move them to dwmac_lib.c. Though in order to have the GPIOs working in the driver the MAC/DMA cleanup methods need to be also defined for that IP-core version. --- .../net/ethernet/stmicro/stmmac/dwmac1000.h | 11 +++++ .../ethernet/stmicro/stmmac/dwmac1000_core.c | 40 +++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/hwif.c | 1 + drivers/net/ethernet/stmicro/stmmac/hwif.h | 1 + 4 files changed, 53 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index 919f5b55bc7d..7fa75e0a33bc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -30,6 +30,7 @@ #define GMAC_INT_STATUS_MMCCSUM BIT(7) #define GMAC_INT_STATUS_TSTAMP BIT(9) #define GMAC_INT_STATUS_LPIIS BIT(10) +#define GMAC_INT_STATUS_GPIIS BIT(11) /* interrupt mask register */ #define GMAC_INT_MASK 0x0000003c @@ -101,6 +102,16 @@ enum power_event { #define GMAC_RGSMIIIS_SPEED_25 0x1 #define GMAC_RGSMIIIS_SPEED_2_5 0x0 +/* General Purpose IO register */ +#define GMAC_GPIO 0x000000e0 /* General Purpose IO */ +#define GMAC_GPIO_GPIS GENMASK(3, 0) +#define GMAC_GPIO_NGPIS 4 +#define GMAC_GPIO_GPO GENMASK(11, 8) +#define GMAC_GPIO_NGPOS 4 +#define GMAC_GPIO_GPIE GENMASK(19, 16) +#define GMAC_GPIO_GPIT GENMASK(27, 24) +#define GMAC_GPIO_NGPIOS (GMAC_GPIO_NGPIS + GMAC_GPIO_NGPOS) + /* GMAC Configuration defines */ #define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */ #define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 7dc8b254c15a..e2a4b746fde9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -12,6 +12,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#include #include #include #include @@ -577,6 +578,45 @@ const struct stmmac_ops dwmac1000_ops = { .set_mac_loopback = dwmac1000_set_mac_loopback, }; +static void dwmac1000_gpio_set_ctrl(struct stmmac_priv *priv, u32 gpie, + u32 gpit, u32 gpo) +{ + u32 val; + + val = FIELD_PREP(GMAC_GPIO_GPO, gpo) | + FIELD_PREP(GMAC_GPIO_GPIE, gpie) | + FIELD_PREP(GMAC_GPIO_GPIT, gpit); + + writel(val, priv->ioaddr + GMAC_GPIO); +} + +static void dwmac1000_gpio_get_ctrl(struct stmmac_priv *priv, u32 *gpie, + u32 *gpit, u32 *gpo) +{ + u32 val; + + val = readl(priv->ioaddr + GMAC_GPIO); + + *gpie = FIELD_GET(GMAC_GPIO_GPIE, val); + *gpit = FIELD_GET(GMAC_GPIO_GPIT, val); + *gpo = FIELD_GET(GMAC_GPIO_GPO, val); +} + +static int dwmac1000_gpio_get_gpi(struct stmmac_priv *priv) +{ + u32 val; + + val = readl(priv->ioaddr + GMAC_GPIO); + + return FIELD_GET(GMAC_GPIO_GPIS, val); +} + +const struct stmmac_gpio_ops dwmac1000_gpio_ops = { + .set_ctrl = dwmac1000_gpio_set_ctrl, + .get_ctrl = dwmac1000_gpio_get_ctrl, + .get_gpi = dwmac1000_gpio_get_gpi, +}; + int dwmac1000_setup(struct stmmac_priv *priv) { struct mac_device_info *mac = priv->hw; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 067420059c11..18aaa27801e4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -140,6 +140,7 @@ static const struct stmmac_hwif_entry { .mode = NULL, .tc = NULL, .mmc = &dwmac_mmc_ops, + .gpio = &dwmac1000_gpio_ops, .setup = dwmac1000_setup, .quirks = stmmac_dwmac1_quirks, }, { diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 99c5841f1060..1aabdd96ea32 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -661,6 +661,7 @@ extern const struct stmmac_ops dwmac100_ops; extern const struct stmmac_dma_ops dwmac100_dma_ops; extern const struct stmmac_ops dwmac1000_ops; extern const struct stmmac_dma_ops dwmac1000_dma_ops; +extern const struct stmmac_gpio_ops dwmac1000_gpio_ops; extern const struct stmmac_ops dwmac4_ops; extern const struct stmmac_dma_ops dwmac4_dma_ops; extern const struct stmmac_ops dwmac410_ops; From patchwork Mon Feb 8 14:08:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 379921 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=unavailable 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 704DCC4332B for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5041164E88 for ; Mon, 8 Feb 2021 14:23:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233103AbhBHOW7 (ORCPT ); Mon, 8 Feb 2021 09:22:59 -0500 Received: from mail.baikalelectronics.com ([87.245.175.226]:57772 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232419AbhBHOKs (ORCPT ); Mon, 8 Feb 2021 09:10:48 -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 16/16] net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions Date: Mon, 8 Feb 2021 17:08:20 +0300 Message-ID: <20210208140820.10410-17-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: netdev@vger.kernel.org DW MAC IPs of the denoted versions have been used on Socfpga Arria10, Baikal-T1 SoC, Intel Socfpga Agilex and Altera Socfpga Stratix10 respectively. Update the Generic DW MAC glue-driver OF-device compatibles to have these IPs accepted so the generic driver would be ready to work with the devices if there were no more specific glue-driver for them. Signed-off-by: Serge Semin --- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index fad503820e04..09246b336499 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -75,6 +75,9 @@ static const struct of_device_id dwmac_generic_match[] = { { .compatible = "snps,dwmac-3.610"}, { .compatible = "snps,dwmac-3.70a"}, { .compatible = "snps,dwmac-3.710"}, + { .compatible = "snps,dwmac-3.72a"}, + { .compatible = "snps,dwmac-3.73a"}, + { .compatible = "snps,dwmac-3.74a"}, { .compatible = "snps,dwmac-4.00"}, { .compatible = "snps,dwmac-4.10a"}, { .compatible = "snps,dwmac"},