netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support
@ 2021-02-08 14:08 Serge Semin
  2021-02-08 14:08 ` [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Serge Semin
                   ` (16 more replies)
  0 siblings, 17 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32,
	linux-arm-kernel, devicetree, linux-kernel

Baikal-T1 SoC is equipped with two Synopsys DesignWare GMAC v3.73a-based
ethernet interfaces. There were no vendor-specific alterations provided
for the synthesized core, but aside with standard configs which can be read
from the DMA-capability registers the GPI/GPO ports were activated. Alas
hardware designers have actively used them to implement the events detection
and to reset PHYs attached to the MAC. So we had no choice, but to somehow fix the
standard STMMAC driver so one would safely support these GPIOs usage.
This series is mainly about introducing the GPI/GPO ports support into
the STMMAC driver and finally adding the Baikal-T1 GMAC support. The later
merely means having a corresponding compatible string added to the OF IDs
list of the Generic DW MAC glue-driver and having the Baikal-T1 GMAC
DT bindings defined in the kernel.

The series starts with fixing the bindings as it was said above, because
the bindings/doc-related patches are supposed to go before the changes
they have been created for.

Then the patchset proceeds with a set of preparation changes, so the
driver would correctly register, work with and de-register the GPIO-chip
in the kernel. The alterations are connected with two problems that made
using the embedded into the MAC GPIOs very hard or even impossible:
(1) MAC/DMA/etc software reset on each network device open.
GPIO-chip is a device which state must be deterministic no matter whether
some network device is opened or released. At least Linux kernel expect it
to act like that. So after the DW MAC GPIO interface is registered in the
kernel we can't let the GPI/GPO stochastically change.  The situation is
getting worse on the platforms (like Baikal-T1 SoC), which can't even
temporarily detach the GPIO pins from the core while for instance the
reset is in progress. To cut it short the only possible solution for such
chips, which also don't have a vendor-specific GPIO-safe reset procedure,
is to get rid of the resets. In the framework of this patchset we suggest
to replace it with MAC and DMA registers manual cleanup in case if MAC
GPIOs are intended to be used. Of course such solution isn't equivalent to
the SW-reset because it doesn't imply the internal state machine reset.
But at least the CSRs state will be as the rest of the code expect them
to.
(2) Main IRQ was requested and unmasked only while network device was opened.
Indeed if we want to use MAC GPIs in the kernel, we must make sure the
input state change is detected by the IRQ handler no matter whether the
network device is opened or not. Of course we could just request the main
IRQ in the probe method and mask all the network-related IRQs while the
corresponding network device is closed. But turned out it wasn't that
easy. Due to a very strange DW MAC IRQs subsystem design we can't
disable/enable and clear/check all the device interrupts in a single CSR.
MAC, DMA, MTL, Safety feature, GPIO subsystems each can generate IRQs and
have got its own CSRs to set the interrupts up. Alas the STMMAC driver
didn't have IP-core-specific callbacks to just disable/enable IRQs from
each of them.  Instead the interrupts were enabled in the framework of the
subsystem functionality setup procedures. So in this patchset we've
introduced a set of MAC, DMA, MTL and Safety feature IRQs enable/disable
callbacks to be able to manually switch on and off all the network-related
interrupts when it's required.

After all of the denoted above problems are fixed we need to get the code
a bit more prepared to adding the GPIOs functionality. Since the driver
ISR will be used to handle both network- and GPIO-related events, it needs
to have a way to determine a time when the network is up and running to
permit the network-related IRQs handling. The best candidate for it is the
STMMAC_DOWN flag which has already been defined in the STMMAC driver. But
the flag semantics was a bit misleading and couldn't be used for our case
out-of-boxi (see the patches log for details). We suggest to fix it by
converting the flag to be STMMAC_UP and being set all the time the network
device is opened.

Finally the GPIOs functionality is introduced. First patch adds a generic
DW MAC GPI/GPO driver, which can be used for any currently available types
of DW *MAC GPIO interfaces. Please see the patch log and its body for the
implementation details (like a reason of the configuration cache usage, a
set of callbacks required to be defined for each GPIO-available DW MAC,
etc). Secondly we've created a set of GPIO-related callbacks to access DW
GMAC GPO/GPI ports so the STMMAC driver would be able to register the
corresponding GPIO-chip for Baikal-T1 GMAC. Note the similar set of
callbacks can be created for DW XGMAC GPIOs, since the GPIO driver has
been designed to be independent from the GPI/GPO CSR implementation. But
aside with them the MAC and DMA cleanup methods need to be introduced to
work around the problem (1) described above in this text.

The series is supposed to be applied on top of the last revision of the
next patchset:
Link: https://lore.kernel.org/netdev/20210208140341.9271-1-Sergey.Semin@baikalelectronics.ru
otherwise a few patches won't get merged in cleanly.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Vyacheslav Mitrofanov <Vyacheslav.Mitrofanov@baikalelectronics.ru>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: netdev@vger.kernel.org
Cc: linux-stm32@st-md-mailman.stormreply.com
Cc: linux-arm-kernel@lists.infradead.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Serge Semin (16):
  dt-bindings: net: dwmac: Add DW GMAC GPIOs properties
  dt-bindings: net: Add Baikal-T1 GMAC bindings
  net: stmmac: Introduce MAC core cleanup method
  net: stmmac: Introduce DMA core cleanup method
  net: stmmac: Introduce MAC IRQs enable/disable methods
  net: stmmac: Extend DMA IRQs enable/disable interface
  net: stmmac: Introduce MTL IRQs enable/disable methods
  net: stmmac: Introduce Safety Feature IRQs enable/disable methods
  net: stmmac: Disable MMC IRQs in the generic IRQs disable method
  net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP
  net: stmmac: Add STMMAC state getter
  net: stmmac: Introduce NIC software reset function
  net: stmmac: Request IRQs at device probe stage
  net: stmmac: Add Generic DW MAC GPIO port driver
  net: stmmac: Add DW GMAC GPIOs support
  net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions

 .../bindings/net/baikal,bt1-gmac.yaml         | 150 +++++++
 .../devicetree/bindings/net/snps,dwmac.yaml   |  17 +
 .../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 +
 .../ethernet/stmicro/stmmac/dwmac-generic.c   |   3 +
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  33 +-
 .../net/ethernet/stmicro/stmmac/dwmac1000.h   |  11 +
 .../ethernet/stmicro/stmmac/dwmac1000_core.c  | 101 ++++-
 .../ethernet/stmicro/stmmac/dwmac1000_dma.c   |   6 +-
 .../ethernet/stmicro/stmmac/dwmac100_dma.c    |   5 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c |  57 ++-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |  17 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  11 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  51 ++-
 drivers/net/ethernet/stmicro/stmmac/dwmac5.c  |  36 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac5.h  |   2 +
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |   7 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |  38 +-
 .../ethernet/stmicro/stmmac/dwxgmac2_core.c   |  76 +++-
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    |  35 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.c    |   3 +
 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  55 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  22 +-
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |   4 +-
 .../net/ethernet/stmicro/stmmac/stmmac_gpio.c | 400 ++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 323 ++++++++++----
 .../ethernet/stmicro/stmmac/stmmac_platform.c |   5 +
 include/linux/stmmac.h                        |   1 +
 30 files changed, 1271 insertions(+), 207 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_gpio.c

-- 
2.29.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-09 23:13   ` Rob Herring
  2021-02-08 14:08 ` [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings Serge Semin
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32,
	linux-arm-kernel, devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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:
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
  2021-02-08 14:08 ` [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-09 23:24   ` Rob Herring
  2021-02-08 14:08 ` [PATCH 03/16] net: stmmac: Introduce MAC core cleanup method Serge Semin
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32,
	linux-arm-kernel, devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>

---

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 <fancer.lancer@gmail.com>
+
+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>;
+      };
+    };
+...
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/16] net: stmmac: Introduce MAC core cleanup method
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
  2021-02-08 14:08 ` [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Serge Semin
  2021-02-08 14:08 ` [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 04/16] net: stmmac: Introduce DMA " Serge Semin
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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...) \
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/16] net: stmmac: Introduce DMA core cleanup method
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (2 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 03/16] net: stmmac: Introduce MAC core cleanup method Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 05/16] net: stmmac: Introduce MAC IRQs enable/disable methods Serge Semin
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 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...) \
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/16] net: stmmac: Introduce MAC IRQs enable/disable methods
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (3 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 04/16] net: stmmac: Introduce DMA " Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 06/16] net: stmmac: Extend DMA IRQs enable/disable interface Serge Semin
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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.
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/16] net: stmmac: Extend DMA IRQs enable/disable interface
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (4 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 05/16] net: stmmac: Introduce MAC IRQs enable/disable methods Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 07/16] net: stmmac: Introduce MTL IRQs enable/disable methods Serge Semin
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>

---

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);
 }
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/16] net: stmmac: Introduce MTL IRQs enable/disable methods
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (5 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 06/16] net: stmmac: Extend DMA IRQs enable/disable interface Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 08/16] net: stmmac: Introduce Safety Feature " Serge Semin
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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);
 }
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/16] net: stmmac: Introduce Safety Feature IRQs enable/disable methods
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (6 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 07/16] net: stmmac: Introduce MTL IRQs enable/disable methods Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 09/16] net: stmmac: Disable MMC IRQs in the generic IRQs disable method Serge Semin
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>

---

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);
 }
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/16] net: stmmac: Disable MMC IRQs in the generic IRQs disable method
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (7 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 08/16] net: stmmac: Introduce Safety Feature " Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 10/16] net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP Serge Semin
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 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);
 }
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/16] net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (8 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 09/16] net: stmmac: Disable MMC IRQs in the generic IRQs disable method Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 11/16] net: stmmac: Add STMMAC state getter Serge Semin
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 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();
 }
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/16] net: stmmac: Add STMMAC state getter
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (9 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 10/16] net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 12/16] net: stmmac: Introduce NIC software reset function Serge Semin
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 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
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/16] net: stmmac: Introduce NIC software reset function
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (10 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 11/16] net: stmmac: Add STMMAC state getter Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 13/16] net: stmmac: Request IRQs at device probe stage Serge Semin
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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;
 	}
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/16] net: stmmac: Request IRQs at device probe stage
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (11 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 12/16] net: stmmac: Introduce NIC software reset function Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 14/16] net: stmmac: Add Generic DW MAC GPIO port driver Serge Semin
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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);
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/16] net: stmmac: Add Generic DW MAC GPIO port driver
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (12 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 13/16] net: stmmac: Request IRQs at device probe stage Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 15/16] net: stmmac: Add DW GMAC GPIOs support Serge Semin
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel, linux-doc

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 <Sergey.Semin@baikalelectronics.ru>
---
 .../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 <linux/ptp_clock_kernel.h>
 #include <linux/net_tstamp.h>
 #include <linux/reset.h>
+#include <linux/gpio/driver.h>
 #include <net/page_pool.h>
 
 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 <Sergey.Semin@baikalelectronics.ru>
+  Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/irq.h>
+#include <linux/stmmac.h>
+
+#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
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/16] net: stmmac: Add DW GMAC GPIOs support
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (13 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 14/16] net: stmmac: Add Generic DW MAC GPIO port driver Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 14:08 ` [PATCH 16/16] net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions Serge Semin
  2021-02-08 19:36 ` [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Andrew Lunn
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>

---

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 <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/bitfield.h>
 #include <linux/crc32.h>
 #include <linux/slab.h>
 #include <linux/ethtool.h>
@@ -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;
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/16] net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (14 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 15/16] net: stmmac: Add DW GMAC GPIOs support Serge Semin
@ 2021-02-08 14:08 ` Serge Semin
  2021-02-08 19:36 ` [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Andrew Lunn
  16 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-08 14:08 UTC (permalink / raw)
  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, netdev, linux-stm32, linux-arm-kernel,
	devicetree, linux-kernel

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 <Sergey.Semin@baikalelectronics.ru>
---
 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"},
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support
  2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
                   ` (15 preceding siblings ...)
  2021-02-08 14:08 ` [PATCH 16/16] net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions Serge Semin
@ 2021-02-08 19:36 ` Andrew Lunn
  2021-02-09 11:16   ` Serge Semin
  16 siblings, 1 reply; 25+ messages in thread
From: Andrew Lunn @ 2021-02-08 19:36 UTC (permalink / raw)
  To: Serge Semin
  Cc: Rob Herring, Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	David S. Miller, Jakub Kicinski, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Mon, Feb 08, 2021 at 05:08:04PM +0300, Serge Semin wrote:

Hi Serge

I suggest you split this patchset up. This uses the generic GPIO
framework, which is great. But that also means you should be Cc: the
GPIO subsystem maintainers and list. But you don't want to spam them
with all the preparation work, which has little to do with the GPIO
code.

So please split the actual GPIO driver and DT binding patches from the
rest. netdev can review the preparation work, with a comment in the
0/X patch about what the big picture is, and then afterwards review
the GPIO patchset with a wider audience.

And as Jakub pointed out, nobody is going to review 60 patches all at
once. Please submit one series at a time, get it merged, and then
move onto the next.

	 Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support
  2021-02-08 19:36 ` [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Andrew Lunn
@ 2021-02-09 11:16   ` Serge Semin
  2021-02-09 14:11     ` Andrew Lunn
  0 siblings, 1 reply; 25+ messages in thread
From: Serge Semin @ 2021-02-09 11:16 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Serge Semin, Rob Herring, Giuseppe Cavallaro, Alexandre Torgue,
	Jose Abreu, David S. Miller, Jakub Kicinski, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Mon, Feb 08, 2021 at 08:36:33PM +0100, Andrew Lunn wrote:
> On Mon, Feb 08, 2021 at 05:08:04PM +0300, Serge Semin wrote:
> 
> Hi Serge
> 
> I suggest you split this patchset up. This uses the generic GPIO
> framework, which is great. But that also means you should be Cc: the
> GPIO subsystem maintainers and list. But you don't want to spam them
> with all the preparation work, which has little to do with the GPIO
> code.
> 
> So please split the actual GPIO driver and DT binding patches from the
> rest. netdev can review the preparation work, with a comment in the
> 0/X patch about what the big picture is, and then afterwards review
> the GPIO patchset with a wider audience.
> 
> And as Jakub pointed out, nobody is going to review 60 patches all at
> once. Please submit one series at a time, get it merged, and then
> move onto the next.

Hello Andrew
Right, with all that preparation work I've forgotten to Cc the
GPIO-subsystem maintainers. Thanks for noticing this.

Regarding the 60-patches. Please see my response to Jakub' post in the
first series. To cut it short let's start working with that patchset:
Link: https://lore.kernel.org/netdev/20210208135609.7685-1-Sergey.Semin@baikalelectronics.ru/
I'll rebase and resubmit the rest of the work when the time comes.

Regarding splitting the series up. I don't see a problem in just
sending the cover-letter patch and actual GPIO-related patches to
the GPIO-maintainers with no need to have them added to Cc in the rest
of the series. That's a normal practice. Splitting is not really
required. But since I have to split the very first patchset anyway.
I'll split this one up too, when it comes to have this part of changes
reviewed.

-Sergey

> 
> 	 Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support
  2021-02-09 11:16   ` Serge Semin
@ 2021-02-09 14:11     ` Andrew Lunn
  2021-02-10 18:00       ` Serge Semin
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Lunn @ 2021-02-09 14:11 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Rob Herring, Giuseppe Cavallaro, Alexandre Torgue,
	Jose Abreu, David S. Miller, Jakub Kicinski, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

> Regarding splitting the series up. I don't see a problem in just
> sending the cover-letter patch and actual GPIO-related patches to
> the GPIO-maintainers with no need to have them added to Cc in the rest
> of the series.

The Linux community has to handle a large number of patches. I don't
particularly want patches which are of no relevance to me landing in
my mailbox. It might take 4 or 5 rounds for the preparation patches to
be accepted. That is 4 or 5 times you are spamming the GPIO
maintainers with stuff which is not relevant to them.

One of the unfortunately things about the kernel process is, there are
a lot of developers, and not many maintainers. So the processes need
to make the life of maintainers easier, and not spamming them helps.

   Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties
  2021-02-08 14:08 ` [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Serge Semin
@ 2021-02-09 23:13   ` Rob Herring
  2021-02-10 22:28     ` Serge Semin
  0 siblings, 1 reply; 25+ messages in thread
From: Rob Herring @ 2021-02-09 23:13 UTC (permalink / raw)
  To: Serge Semin
  Cc: Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	David S. Miller, Jakub Kicinski, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Mon, Feb 08, 2021 at 05:08:05PM +0300, Serge Semin wrote:
> 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 <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../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

Does the driver actually need this? I'd omit it if just to validate 
consumers are in range.

Are GPI and GPO counts independent? If so, this isn't really sufficient.

Rob

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings
  2021-02-08 14:08 ` [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings Serge Semin
@ 2021-02-09 23:24   ` Rob Herring
  0 siblings, 0 replies; 25+ messages in thread
From: Rob Herring @ 2021-02-09 23:24 UTC (permalink / raw)
  To: Serge Semin
  Cc: Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	David S. Miller, Jakub Kicinski, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Mon, Feb 08, 2021 at 05:08:06PM +0300, Serge Semin wrote:
> 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 <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> 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?

Yes, that's known problem which I don't have a solution for. I think the 
solution is checking all properties have a type defined once and only 
once. That would also make sure we don't have 2 property names with 
different types. With that we can loosen the meta-schema checks. In the 
vast majority of cases though we need a type, so the exceptions like 
here will need to duplicate the type and description.


Reviewed-by: Rob Herring <robh@kernel.org>

> ---
>  .../bindings/net/baikal,bt1-gmac.yaml         | 150 ++++++++++++++++++
>  1 file changed, 150 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/baikal,bt1-gmac.yaml

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support
  2021-02-09 14:11     ` Andrew Lunn
@ 2021-02-10 18:00       ` Serge Semin
  0 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-10 18:00 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Serge Semin, Rob Herring, Giuseppe Cavallaro, Alexandre Torgue,
	Jose Abreu, David S. Miller, Jakub Kicinski, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Tue, Feb 09, 2021 at 03:11:41PM +0100, Andrew Lunn wrote:
> > Regarding splitting the series up. I don't see a problem in just
> > sending the cover-letter patch and actual GPIO-related patches to
> > the GPIO-maintainers with no need to have them added to Cc in the rest
> > of the series.
> 

> The Linux community has to handle a large number of patches. I don't
> particularly want patches which are of no relevance to me landing in
> my mailbox. It might take 4 or 5 rounds for the preparation patches to
> be accepted. That is 4 or 5 times you are spamming the GPIO
> maintainers with stuff which is not relevant to them.

I don't really understand what you are arguing with. My suggestion
didn't contradict to what you said. I exactly meant to omit sending
the patches to GPIO maintainers, which they had no relevance to. So
they wouldn't be spammed with unwanted patches. The GPIO maintainers
can be Cc/To-ed only to the messages with GPIO-related patches. It's
normal to have intermixed patchsets, but to post individual patches to
the maintainers they might be interested in or they need to review. So
splitting up isn't required in this case.  Moreover doing as you
suggest would extend the time of the patches review with no really
much gain in the emailing activity optimization.

> 
> One of the unfortunately things about the kernel process is, there are
> a lot of developers, and not many maintainers. So the processes need
> to make the life of maintainers easier, and not spamming them helps.

Can't argue with that.)

-Sergey

> 
>    Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties
  2021-02-09 23:13   ` Rob Herring
@ 2021-02-10 22:28     ` Serge Semin
  2021-02-18 15:52       ` Serge Semin
  0 siblings, 1 reply; 25+ messages in thread
From: Serge Semin @ 2021-02-10 22:28 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	David S. Miller, Jakub Kicinski, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Tue, Feb 09, 2021 at 05:13:52PM -0600, Rob Herring wrote:
> On Mon, Feb 08, 2021 at 05:08:05PM +0300, Serge Semin wrote:
> > 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 <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  .../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
> 

> Does the driver actually need this? I'd omit it if just to validate 
> consumers are in range.

I can't say for all possible DW MAC IP-cores (I've got manuals for
GMAC and xGMAC only), but at least DW GMAC can't have more than four
GPIs and four GPOs, while XGMACs can be synthesized with up to 16
each. That's why I've set the upper boundary here as 32. But the
driver uses the ngpios property do determine the total number GPIOs
the core has been synthesized. Th number of GPIs and GPOs will be
auto-detected then (by writing-reading to-from the GPI type field of
the GPIO control register).

> 
> Are GPI and GPO counts independent? If so, this isn't really sufficient.

Yeap, they are independent. What do you suggest then? Define some
vendor-specific properties like snps,ngpis and snps,ngpos? If so then
they seem more generic than vendor-specific, because the separated
GPI and GPO space isn't an unique feature of the DW MAC GPIOs. Do we
need to create a generic version of such properties then? (That much
more changes then introduced here. We'd need to fix the dt-schema tool
too then.)

-Sergey

> 
> Rob

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties
  2021-02-10 22:28     ` Serge Semin
@ 2021-02-18 15:52       ` Serge Semin
  0 siblings, 0 replies; 25+ messages in thread
From: Serge Semin @ 2021-02-18 15:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	David S. Miller, Jakub Kicinski, Alexey Malahov,
	Pavel Parkhomenko, Vyacheslav Mitrofanov, Maxime Coquelin,
	netdev, linux-stm32, linux-arm-kernel, devicetree, linux-kernel

On Thu, Feb 11, 2021 at 01:28:06AM +0300, Serge Semin wrote:
> On Tue, Feb 09, 2021 at 05:13:52PM -0600, Rob Herring wrote:
> > On Mon, Feb 08, 2021 at 05:08:05PM +0300, Serge Semin wrote:
> > > 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 <Sergey.Semin@baikalelectronics.ru>
> > > ---
> > >  .../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
> > 
> 

> > Does the driver actually need this? I'd omit it if just to validate 
> > consumers are in range.
> 
> I can't say for all possible DW MAC IP-cores (I've got manuals for
> GMAC and xGMAC only), but at least DW GMAC can't have more than four
> GPIs and four GPOs, while XGMACs can be synthesized with up to 16
> each. That's why I've set the upper boundary here as 32. But the
> driver uses the ngpios property do determine the total number GPIOs
> the core has been synthesized. Th number of GPIs and GPOs will be
> auto-detected then (by writing-reading to-from the GPI type field of
> the GPIO control register).
> 
> > 
> > Are GPI and GPO counts independent? If so, this isn't really sufficient.
> 
> Yeap, they are independent. What do you suggest then? Define some
> vendor-specific properties like snps,ngpis and snps,ngpos? If so then
> they seem more generic than vendor-specific, because the separated
> GPI and GPO space isn't an unique feature of the DW MAC GPIOs. Do we
> need to create a generic version of such properties then? (That much
> more changes then introduced here. We'd need to fix the dt-schema tool
> too then.)
> 
> -Sergey

Rob, any comment on my questions above? As the kernel is in
merge-window now, I just hope this part won't get pushed back in the
emails log out of your sight.

-Sergey

> 
> > 
> > Rob

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2021-02-18 17:39 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-08 14:08 [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Serge Semin
2021-02-08 14:08 ` [PATCH 01/16] dt-bindings: net: dwmac: Add DW GMAC GPIOs properties Serge Semin
2021-02-09 23:13   ` Rob Herring
2021-02-10 22:28     ` Serge Semin
2021-02-18 15:52       ` Serge Semin
2021-02-08 14:08 ` [PATCH 02/16] dt-bindings: net: Add Baikal-T1 GMAC bindings Serge Semin
2021-02-09 23:24   ` Rob Herring
2021-02-08 14:08 ` [PATCH 03/16] net: stmmac: Introduce MAC core cleanup method Serge Semin
2021-02-08 14:08 ` [PATCH 04/16] net: stmmac: Introduce DMA " Serge Semin
2021-02-08 14:08 ` [PATCH 05/16] net: stmmac: Introduce MAC IRQs enable/disable methods Serge Semin
2021-02-08 14:08 ` [PATCH 06/16] net: stmmac: Extend DMA IRQs enable/disable interface Serge Semin
2021-02-08 14:08 ` [PATCH 07/16] net: stmmac: Introduce MTL IRQs enable/disable methods Serge Semin
2021-02-08 14:08 ` [PATCH 08/16] net: stmmac: Introduce Safety Feature " Serge Semin
2021-02-08 14:08 ` [PATCH 09/16] net: stmmac: Disable MMC IRQs in the generic IRQs disable method Serge Semin
2021-02-08 14:08 ` [PATCH 10/16] net: stmmac: Convert STMMAC_DOWN flag to STMMAC_UP Serge Semin
2021-02-08 14:08 ` [PATCH 11/16] net: stmmac: Add STMMAC state getter Serge Semin
2021-02-08 14:08 ` [PATCH 12/16] net: stmmac: Introduce NIC software reset function Serge Semin
2021-02-08 14:08 ` [PATCH 13/16] net: stmmac: Request IRQs at device probe stage Serge Semin
2021-02-08 14:08 ` [PATCH 14/16] net: stmmac: Add Generic DW MAC GPIO port driver Serge Semin
2021-02-08 14:08 ` [PATCH 15/16] net: stmmac: Add DW GMAC GPIOs support Serge Semin
2021-02-08 14:08 ` [PATCH 16/16] net: stmmac: Add DW MAC IPs of 3.72a/3.73a/3.74a versions Serge Semin
2021-02-08 19:36 ` [PATCH 00/16] net: stmmac: Add DW MAC GPIOs and Baikal-T1 GMAC support Andrew Lunn
2021-02-09 11:16   ` Serge Semin
2021-02-09 14:11     ` Andrew Lunn
2021-02-10 18:00       ` Serge Semin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).