All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support
@ 2022-03-24  0:16 Serge Semin
  2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
                   ` (21 more replies)
  0 siblings, 22 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

The main goal of this patchset was to add Baikal-T1 AHCI SATA specifics
support into the kernel AHCI subsystem. On the way of doing that we
figured out that mainly these specifics are actually DWC AHCI SATA
controller features, but still there were some Baikal-T1 SoC platform
peculiarities which we had to take into account. So the patchset
introduces two AHCI SATA controllers support and one AHCI SATA driver
with a series of preparation, optimization and cleanup patches.

Traditionally the series starts with converting the legacy AHCI SATA
controllers text-based DT-bindings to the DT-schema. The bindings are
split up into two schemas: one common AHCI SATA controller yaml-file,
which can be reused by any AHCI-compatible controller utilizing the kernel
AHCI library functions, and DT-bindings for the generic AHCI SATA devices
indicated by the "generic-ahci" compatible string and implemented in the
ahci_platform.c driver. Note before doing that we had to fix the
sata-common.yaml file SATA port IDs constraint.

Then a series of generic preparations-cleanups goes. First of all it
concerns the device-managed methods usage in the framework of the CSR
space remapping and the clocks requesting and enabling. Note since the
clocks handlers are requested and kept in the generic AHCI library it
seemed a good idea to add an AHCI-platform generic method to find and get
a particular clock handler from the pool of the requested ones. It was
used later in the series in the DWC/Baikal-T1-specific code. Secondly we
suggested to at least sanity check the number of SATA ports DT-sub-nodes
before using it further.  Thirdly the ports-implemented DT-property
parsing was moved from the AHCI platform-driver to the AHCI-library so to
be used by the non-generic AHCI drivers if required (DT-schema is
accordingly fixed too). Finally due to having the shared-reset control
support we had to add a new AHCI-resource getter flag -
AHCI_PLATFORM_RST_TRIGGER, which indicated using a trigger-like reset
control. For such platforms the controller reset will be performed by
means of the reset_control_reset() and reset_control_rearm() methods.
AHCI-library reset functions encapsulating the way the reset procedure is
performed have been also added.

After that goes a patches series with the platform-specific
AHCI-capabilities initialization. The suggested functionality will be
useful for the platforms with no BIOS, comprehensive bootloader/firmware
installed. In that case the AHCI-related platform-specifics like drive
staggered spin-up, mechanical presence switch attached or FIS-based
switching capability usage, etc will be left uninitialized with no generic
way to be indicated as available if required. We suggested to use the AHCI
device tree node and its ports sub-nodes for that. AHCI-platform library
will be responsible fo the corresponding DT-properties parsing and
pre-initialization of the internal capability registers cache, which will
be then flashed back to the corresponding CSR after HBA reset. Thus a
supposed to be firmware-work will be done by means of the AHCI-library and
the DT-data. A set of the preparations/cleanups required to be done before
introducing the feature.  First the DT-properties indicating the
corresponding capability availability were described in the common AHCI
DT-binding schema. Second we needed to add the enum items with the AHCI
Port CMD fields, which hadn't been added so far. Thirdly we suggested to
discard one of the port-map internal storage (force_port_map) in favor of
re-using another one (save_port_map) in order to simplify the port-map
initialization interface a bit by getting rid from a redundant variable.
Finally after discarding the double AHCI-version read procedure and
changing the __ahci_port_base() method prototype the platform
firmware-specific caps initialization functionality was introduced.

The main part of the series goes afterwards. A dedicated DWC AHCI SATA
controller driver was introduced together with the corresponding
DT-binding schema pre-patch. Note the driver built mode is activated
synchronously with the generic AHCI-platform driver by default so
automatically to be integrated into the kernel for the DWC AHCI-based
platforms which relied on activating the generic AHCI SATA controller
driver. Aside with the generic resources getting and AHCI-host
initialization, the driver implements the DWC-specific setups. In
particular it checks whether the platform capabilities activated by the
firmware (see the functionality described above) are actually supported by
the controller. It's done by means of the vendor-specific registers. Then
it makes sure that the embedded 1ms timer interval, which is used for the
DevSleep and CCC features, is correctly initialized based on the
application clock rate.  The last but not least the driver provides a way
to tune the DMA-interface performance up by setting the Tx/Rx transactions
maximum size up. The required values are specified by means of the
"snps,tx-ts-max" and snps,rx-ts-max" DT-properties.

Finally we suggest to extend the DWC AHCI SATA controller driver
functionality with a way to add the DWC-AHCI-based platform-specific
quirks. Indeed there are many DWC AHCI-based controllers and just a few of
them are diverged too much to be handled by a dedicated AHCI-driver. The
rest of them most likely can work well either with a generic version of
the driver or require a simple normally platform-specific quirk to get up
and running. Such platforms can define a platform-data in the DWC AHCI
driver with a set of the controller-specific flags and initialization
functions. Those functions will be called at the corresponding stages of
the device probe/resume/remove procedures so to be performing the platform
setups/cleanups.

After the denoted above functionality is added we can finally introduce
the Baikal-T1 AHCI SATA controller support into the DWC AHCI SATA driver.
The controller is based on the DWC AHCI SATA IP-core v4.10a and can work
well with the generic DWC AHCI driver. The only peculiarity of it is
connected with the SATA Ports reference clock source. It can be supplied
either from the internal SoC PLL or from the chip pads. Currently we have
to prefer selecting the signal coming from the pads if the corresponding
clock source is specified because the link doesn't get stably established
when the internal clock signal is activated. In addition the platform has
trigger-based reset signals so the corresponding flag must be passed to
the generic AHCI-resource getter.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-ide@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org

Serge Semin (21):
  dt-bindings: ata: sata: Extend number of SATA ports
  dt-bindings: ata: Convert AHCI-bindings to DT schema
  ata: libahci_platform: Explicitly set rc on devres_alloc failure
  ata: libahci_platform: Convert to using handy devm-ioremap methods
  ata: libahci_platform: Convert to using devm bulk clocks API
  ata: libahci_platform: Add function returning a clock-handle by id
  ata: libahci_platform: Sanity check the DT child nodes number
  ata: libahci_platform: Parse ports-implemented property in resources
    getter
  ata: libahci_platform: Introduce reset assertion/deassertion methods
  dt-bindings: ata: ahci: Add platform capability properties
  ata: libahci: Extend port-cmd flags set with port capabilities
  ata: libahci: Discard redundant force_port_map parameter
  ata: libahci: Don't read AHCI version twice in the save-config method
  ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
  ata: ahci: Introduce firmware-specific caps initialization
  dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
  ata: ahci: Add DWC AHCI SATA controller support
  dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
  ata: ahci-dwc: Add platform-specific quirks support
  ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
  MAINTAINERS: Add maintainers for DWC AHCI SATA driver

 .../devicetree/bindings/ata/ahci-common.yaml  | 176 ++++++
 .../devicetree/bindings/ata/ahci-platform.txt |  79 ---
 .../bindings/ata/baikal,bt1-ahci.yaml         | 132 +++++
 .../devicetree/bindings/ata/generic-ahci.yaml |  98 ++++
 .../devicetree/bindings/ata/sata-common.yaml  |   7 +-
 .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++
 MAINTAINERS                                   |   9 +
 drivers/ata/Kconfig                           |  11 +
 drivers/ata/Makefile                          |   1 +
 drivers/ata/ahci.c                            |   4 +-
 drivers/ata/ahci.h                            |  21 +-
 drivers/ata/ahci_dwc.c                        | 525 ++++++++++++++++++
 drivers/ata/ahci_mtk.c                        |   2 -
 drivers/ata/ahci_platform.c                   |   5 -
 drivers/ata/ahci_st.c                         |   3 -
 drivers/ata/libahci.c                         |  63 ++-
 drivers/ata/libahci_platform.c                | 234 +++++---
 include/linux/ahci_platform.h                 |   8 +-
 18 files changed, 1321 insertions(+), 178 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
 delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
 create mode 100644 Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
 create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml
 create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
 create mode 100644 drivers/ata/ahci_dwc.c

-- 
2.35.1


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

* [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-29  8:15   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema Serge Semin
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Rob Herring, Linus Walleij
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	linux-ide, linux-kernel, devicetree

The denoted in the description upper limit only concerns the Port
Multipliers, but not the actual SATA ports. It's an external device
attached to a SATA port in order to access more than one SATA-drive. So
when it's attached to a SATA port it just extends the port capability
while the number of actual SATA ports stays the same. For instance on AHCI
controllers the number of actual ports is determined by the CAP.NP field
and the PI (Ports Implemented) register. AFAICS in general the maximum
number of SATA ports depends on the particular controller implementation.
Generic AHCI controller can't have more than 32 ports (since CAP.NP is of
5 bits wide and PI register is 32-bits size), while DWC AHCI SATA
controller can't be configured with more than 8 ports activated. So let's
discard the SATA ports reg-property restrictions and just make sure that
it consists of a single reg-item.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 Documentation/devicetree/bindings/ata/sata-common.yaml | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/ata/sata-common.yaml b/Documentation/devicetree/bindings/ata/sata-common.yaml
index 7ac77b1c5850..c619f0ae72fb 100644
--- a/Documentation/devicetree/bindings/ata/sata-common.yaml
+++ b/Documentation/devicetree/bindings/ata/sata-common.yaml
@@ -41,11 +41,10 @@ patternProperties:
     properties:
       reg:
         minimum: 0
-        maximum: 14
         description:
-          The ID number of the drive port SATA can potentially use a port
-          multiplier making it possible to connect up to 15 disks to a single
-          SATA port.
+          The ID number of the SATA port. Aside with being directly used
+          each port can have a Port Multiplier attached thus allowing to
+          access more than one drive by means of a single channel.
 
 additionalProperties: true
 
-- 
2.35.1


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

* [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
  2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-28 19:32   ` Rob Herring
  2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Rob Herring
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	linux-ide, linux-kernel, devicetree

Currently the DT bindings of Generic AHCI Controllers are described by
means of the legacy text file. Since such format is deprecated in favor of
the DT schema. Let's convert the Generic AHCI Controllers bindings file
then to the corresponding yaml files. There will be two of them: a DT
schema with a set of properties applied to all AHCI-compatible devices,
and a DT schema validating an AHCI-controller on a generic platform. So if
a controller conforms to the Serial ATA AHCI interface specification with
just peculiar platform environment settings like clock sources, PHYs,
power regulators or resets, then the generic AHCI bindings should work for
it. Otherwise a dedicated DT-schema needs to be created.

So a common AHCI SATA controller DT-node is supposed to be equipped with
at least compatible, reg and interrupts properties. It can optionally
contain clocks, resets, {ahci,target,phy}-supply and phys phandles. In
addition the property "ports-implemented" can be specified in order to
define the number of implemented SATA ports. An AHCI SATA controller
DT-node can also have a set of sub-nodes representing its ports, for each
of which an individual power source and PHY phandle can be specified.

Note we have omitted the next compatible strings
"marvell,armada-380-ahci", "marvell,armada-3700-ahci", "snps,dwc-ahci",
"snps,spear-ahci" since the corresponding controllers are handled by the
dedicated drivers now, thus are supposed to have their own DT-schema
defined. dma-coherent has also been discarded since it's a generic
property and is evaluated by the dt-schema parser.

Also note that if there is the "reg-names" property specified for a AHCI
DT-node then it is supposed to at least have the "ahci" sub-string as an
indicator of the AHCI-compatible registers space.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../devicetree/bindings/ata/ahci-common.yaml  | 110 ++++++++++++++++++
 .../devicetree/bindings/ata/ahci-platform.txt |  79 -------------
 .../devicetree/bindings/ata/generic-ahci.yaml |  89 ++++++++++++++
 3 files changed, 199 insertions(+), 79 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
 delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
 create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml

diff --git a/Documentation/devicetree/bindings/ata/ahci-common.yaml b/Documentation/devicetree/bindings/ata/ahci-common.yaml
new file mode 100644
index 000000000000..054819930538
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/ahci-common.yaml
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ata/ahci-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Common Properties for Serial ATA AHCI controllers
+
+maintainers:
+  - Hans de Goede <hdegoede@redhat.com>
+  - Jens Axboe <axboe@kernel.dk>
+
+description: |
+  This document defines device tree properties for a common AHCI SATA
+  controller implementation. It's hardware interface is supposed to
+  conform to the technical standard defined by Intel (see Serial ATA
+  Advanced Host Controller Interface specification for details). The
+  document doesn't constitute a DT-node binding by itself but merely
+  defines a set of common properties for the AHCI-compatible devices.
+
+select: false
+
+allOf:
+  - $ref: sata-common.yaml#
+
+properties:
+  reg:
+    description:
+      Generic AHCI registers space conforming to the Serial ATA AHCI
+      specification.
+
+  reg-names:
+    contains:
+      const: ahci
+
+  interrupts:
+    description:
+      Generic AHCI state change interrupt. Can be implemented either as a
+      single lane attached to the controller for all global and ports events
+      or as a set of signals for the global and each port.
+
+  clocks:
+    description:
+      List of all the reference clocks connected to the controller.
+
+  clock-names:
+    description: Reference clocks IDs
+
+  resets:
+    description:
+      List of all the reset control lines to successfully reset the
+      controller clock domains.
+
+  ahci-supply:
+    description: Power regulator for AHCI controller
+
+  target-supply:
+    description: Power regulator for SATA target device
+
+  phy-supply:
+    description: Power regulator for SATA PHY
+
+  phys:
+    description: Reference to the SATA PHY node
+    maxItems: 1
+
+  phy-names:
+    const: sata-phy
+
+  ports-implemented:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Mask that indicates which ports the HBA supports. Useful if PI is not
+      programmed by the BIOS, which is true for some embedded SoC's.
+
+patternProperties:
+  "^sata-port@[0-9a-e]$":
+    description:
+      It is optionally possible to describe the ports as sub-nodes so
+      to enable each port independently when dealing with multiple PHYs.
+    type: object
+
+    properties:
+      reg:
+        description:
+          By design AHCI controller can't work with more than 32 ports
+          due to the CAP.NP fields and PI register size constraints.
+        minimum: 0
+        maximum: 31
+
+      phys:
+        description: Individual AHCI SATA port PHY
+        maxItems: 1
+
+      phy-names:
+        const: sata-phy
+
+      target-supply:
+        description: Power regulator for SATA port target device
+
+    required:
+      - reg
+
+required:
+  - reg
+  - interrupts
+
+additionalProperties: true
+
+...
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
deleted file mode 100644
index 77091a277642..000000000000
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-* AHCI SATA Controller
-
-SATA nodes are defined to describe on-chip Serial ATA controllers.
-Each SATA controller should have its own node.
-
-It is possible, but not required, to represent each port as a sub-node.
-It allows to enable each port independently when dealing with multiple
-PHYs.
-
-Required properties:
-- compatible        : compatible string, one of:
-  - "brcm,iproc-ahci"
-  - "hisilicon,hisi-ahci"
-  - "cavium,octeon-7130-ahci"
-  - "ibm,476gtr-ahci"
-  - "marvell,armada-380-ahci"
-  - "marvell,armada-3700-ahci"
-  - "snps,dwc-ahci"
-  - "snps,spear-ahci"
-  - "generic-ahci"
-- interrupts        : <interrupt mapping for SATA IRQ>
-- reg               : <registers mapping>
-
-Please note that when using "generic-ahci" you must also specify a SoC specific
-compatible:
-	compatible = "manufacturer,soc-model-ahci", "generic-ahci";
-
-Optional properties:
-- dma-coherent      : Present if dma operations are coherent
-- clocks            : a list of phandle + clock specifier pairs
-- resets            : a list of phandle + reset specifier pairs
-- target-supply     : regulator for SATA target power
-- phy-supply        : regulator for PHY power
-- phys              : reference to the SATA PHY node
-- phy-names         : must be "sata-phy"
-- ahci-supply       : regulator for AHCI controller
-- ports-implemented : Mask that indicates which ports that the HBA supports
-		      are available for software to use. Useful if PORTS_IMPL
-		      is not programmed by the BIOS, which is true with
-		      some embedded SOC's.
-
-Required properties when using sub-nodes:
-- #address-cells    : number of cells to encode an address
-- #size-cells       : number of cells representing the size of an address
-
-Sub-nodes required properties:
-- reg		    : the port number
-And at least one of the following properties:
-- phys		    : reference to the SATA PHY node
-- target-supply     : regulator for SATA target power
-
-Examples:
-        sata@ffe08000 {
-		compatible = "snps,spear-ahci";
-		reg = <0xffe08000 0x1000>;
-		interrupts = <115>;
-        };
-
-With sub-nodes:
-	sata@f7e90000 {
-		compatible = "marvell,berlin2q-achi", "generic-ahci";
-		reg = <0xe90000 0x1000>;
-		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&chip CLKID_SATA>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		sata0: sata-port@0 {
-			reg = <0>;
-			phys = <&sata_phy 0>;
-			target-supply = <&reg_sata0>;
-		};
-
-		sata1: sata-port@1 {
-			reg = <1>;
-			phys = <&sata_phy 1>;
-			target-supply = <&reg_sata1>;;
-		};
-	};
diff --git a/Documentation/devicetree/bindings/ata/generic-ahci.yaml b/Documentation/devicetree/bindings/ata/generic-ahci.yaml
new file mode 100644
index 000000000000..957f45c4f488
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/generic-ahci.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ata/generic-ahci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic AHCI SATA controller
+
+maintainers:
+  - Hans de Goede <hdegoede@redhat.com>
+  - Jens Axboe <axboe@kernel.dk>
+
+description: |
+  This document defines device tree bindings for the controllers conforming
+  to the generic AHCI SATA interface.
+
+allOf:
+  - $ref: ahci-common.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - description: Generic AHCI SATA device
+        const: generic-ahci
+      - description: Broadcom IPROC AHCI SATA device
+        items:
+          - const: brcm,iproc-ahci
+          - const: generic-ahci
+      - description: HiSilicon AHCI SATA device
+        const: hisilicon,hisi-ahci
+      - description: Cavium Octeon 7130 AHCI SATA device
+        const: octeon-7130-ahci
+      - description: IBM Akebono AHCI SATA device
+        const: ibm,476gtr-ahci
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/hix5hd2-clock.h>
+
+    sata@1900000 {
+      compatible = "hisilicon,hisi-ahci";
+      reg = <0x1900000 0x10000>;
+
+      interrupts = <0 70 4>;
+
+      clocks = <&clock HIX5HD2_SATA_CLK>;
+
+      phys = <&sata_phy>;
+      phy-names = "sata-phy";
+    };
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    sata@663f2000 {
+      compatible = "brcm,iproc-ahci", "generic-ahci";
+      reg = <0x663f2000 0x1000>;
+      reg-names = "ahci";
+      #address-cells = <1>;
+      #size-cells = <0>;
+      dma-coherent;
+
+      interrupts = <GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>;
+
+      sata-port@0 {
+        reg = <0>;
+        phys = <&sata_phy0>;
+        phy-names = "sata-phy";
+      };
+
+      sata-port@1 {
+        reg = <1>;
+        phys = <&sata_phy1>;
+        phy-names = "sata-phy";
+      };
+    };
+...
-- 
2.35.1


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

* [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
  2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
  2022-03-24  0:16 ` [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:58   ` Damien Le Moal
  2022-03-29  8:20   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods Serge Semin
                   ` (18 subsequent siblings)
  21 siblings, 2 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

It's better for readability and maintainability to explicitly assign an
error number to the variable used then as a return value from the method
on the cleanup-on-error path. So adding new code in the method we won't
have to think whether the overridden rc-variable is set afterward in case
of an error. Saving one line of code doesn't worth it especially seeing
the rest of the ahci_platform_get_resources() function errors handling
blocks do explicitly write errno to rc.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/libahci_platform.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 18296443ccba..1bd2f1686239 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 	struct ahci_host_priv *hpriv;
 	struct clk *clk;
 	struct device_node *child;
-	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
+	int i, enabled_ports = 0, rc = 0, child_nodes;
 	u32 mask_port_map = 0;
 
 	if (!devres_open_group(dev, NULL, GFP_KERNEL))
@@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 
 	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
 			     GFP_KERNEL);
-	if (!hpriv)
+	if (!hpriv) {
+		rc = -ENOMEM;
 		goto err_out;
+	}
 
 	devres_add(dev, hpriv);
 
-- 
2.35.1


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

* [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (2 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  1:11   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Currently the IOMEM AHCI registers space is mapped by means of the
two functions invocation: platform_get_resource() is used to get the very
first memory resource and devm_ioremap_resource() is called to remap that
resource. Device-managed kernel API provides a handy wrapper to perform
the same in single function call: devm_platform_ioremap_resource().

While at it seeing many AHCI platform drivers rely on having the AHCI CSR
space marked with "ahci" name let's first try to find and remap the CSR
IO-mem with that name and only if it fails fallback to getting the very
first registers space platform resource.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/libahci_platform.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 1bd2f1686239..8eabbb5f208c 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -404,11 +404,13 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 
 	devres_add(dev, hpriv);
 
-	hpriv->mmio = devm_ioremap_resource(dev,
-			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");
 	if (IS_ERR(hpriv->mmio)) {
-		rc = PTR_ERR(hpriv->mmio);
-		goto err_out;
+		hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
+		if (IS_ERR(hpriv->mmio)) {
+			rc = PTR_ERR(hpriv->mmio);
+			goto err_out;
+		}
 	}
 
 	for (i = 0; i < AHCI_MAX_CLKS; i++) {
-- 
2.35.1


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

* [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (3 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  1:29   ` Damien Le Moal
                     ` (3 more replies)
  2022-03-24  0:16 ` [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id Serge Semin
                   ` (16 subsequent siblings)
  21 siblings, 4 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

In order to simplify the clock-related code there is a way to convert the
current fixed clocks array into using the common bulk clocks kernel API
with dynamic set of the clock handlers and device-managed clock-resource
tracking. It's a bit tricky due to the complication coming from the
requirement to support the platforms (da850, spear13xx) with the
non-OF-based clock source, but still doable.

Before this modification there are two methods have been used to get the
clocks connected to an AHCI device: clk_get() - to get the very first
clock in the list and of_clk_get() - to get the rest of them. Basically
the platforms with non-OF-based clocks definition could specify only a
single reference clock source. The platforms with OF-hw clocks have been
luckier and could setup up to AHCI_MAX_CLKS clocks. Such semantic can be
retained with using devm_clk_bulk_get_all() to retrieve the clocks defined
via the DT firmware and devm_clk_get_optional() otherwise. In both cases
using the device-managed version of the methods will cause the automatic
resources deallocation on the AHCI device removal event. The only
complicated part in the suggested approach is the explicit allocation and
initialization of the clk_bulk_data structure instance for the non-OF
reference clocks. It's required in order to use the Bulk Clocks API for
the both denoted cases of the clocks definition.

Note aside with the clock-related code reduction and natural
simplification, there are several bonuses the suggested modification
provides. First of all the limitation of having no greater than
AHCI_MAX_CLKS clocks is now removed, since the devm_clk_bulk_get_all()
method will allocate as many reference clocks data descriptors as there
are clocks specified for the device. Secondly the clock names are
auto-detected. So the glue drivers can make sure that the required clocks
are specified just by checking the clock IDs in the clk_bulk_data array.
Thirdly using the handy Bulk Clocks kernel API improves the
clocks-handling code readability. And the last but not least this
modification implements a true optional clocks support to the
ahci_platform_get_resources() method. Indeed the previous clocks getting
procedure just stopped getting the clocks on any errors (aside from
non-critical -EPROBE_DEFER) in a way so the callee wasn't even informed
about abnormal loop termination. The new implementation lacks of such
problem. The ahci_platform_get_resources() will return an error code if
the corresponding clocks getting method ends execution abnormally.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.h             |  4 +-
 drivers/ata/libahci_platform.c | 82 +++++++++++++++-------------------
 2 files changed, 37 insertions(+), 49 deletions(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index eeac5482f1d1..1564c691094a 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -38,7 +38,6 @@
 
 enum {
 	AHCI_MAX_PORTS		= 32,
-	AHCI_MAX_CLKS		= 5,
 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
 	AHCI_DMA_BOUNDARY	= 0xffffffff,
 	AHCI_MAX_CMDS		= 32,
@@ -341,7 +340,8 @@ struct ahci_host_priv {
 	u32			em_msg_type;	/* EM message type */
 	u32			remapped_nvme;	/* NVMe remapped device count */
 	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
-	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
+	unsigned int		n_clks;
+	struct clk_bulk_data	*clks;		/* Optional */
 	struct reset_control	*rsts;		/* Optional */
 	struct regulator	**target_pwrs;	/* Optional */
 	struct regulator	*ahci_regulator;/* Optional */
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 8eabbb5f208c..d805ddc3a024 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -8,6 +8,7 @@
  *   Anton Vorontsov <avorontsov@ru.mvista.com>
  */
 
+#include <linux/clk-provider.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/gfp.h>
@@ -97,28 +98,14 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
  * ahci_platform_enable_clks - Enable platform clocks
  * @hpriv: host private area to store config values
  *
- * This function enables all the clks found in hpriv->clks, starting at
- * index 0. If any clk fails to enable it disables all the clks already
- * enabled in reverse order, and then returns an error.
+ * This function enables all the clks found for the AHCI device.
  *
  * RETURNS:
  * 0 on success otherwise a negative error code
  */
 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
 {
-	int c, rc;
-
-	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
-		rc = clk_prepare_enable(hpriv->clks[c]);
-		if (rc)
-			goto disable_unprepare_clk;
-	}
-	return 0;
-
-disable_unprepare_clk:
-	while (--c >= 0)
-		clk_disable_unprepare(hpriv->clks[c]);
-	return rc;
+	return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
 }
 EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
 
@@ -126,16 +113,13 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
  * ahci_platform_disable_clks - Disable platform clocks
  * @hpriv: host private area to store config values
  *
- * This function disables all the clks found in hpriv->clks, in reverse
- * order of ahci_platform_enable_clks (starting at the end of the array).
+ * This function disables all the clocks enabled before
+ * (bulk-clocks-disable function is supposed to do that in reverse
+ * from the enabling procedure order).
  */
 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
 {
-	int c;
-
-	for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
-		if (hpriv->clks[c])
-			clk_disable_unprepare(hpriv->clks[c]);
+	clk_bulk_disable_unprepare(hpriv->n_clks, hpriv->clks);
 }
 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
 
@@ -292,8 +276,6 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
 		pm_runtime_disable(dev);
 	}
 
-	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
-		clk_put(hpriv->clks[c]);
 	/*
 	 * The regulators are tied to child node device and not to the
 	 * SATA device itself. So we can't use devm for automatically
@@ -374,8 +356,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
  * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
  * 2) regulator for controlling the targets power (optional)
  *    regulator for controlling the AHCI controller (optional)
- * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
- *    or for non devicetree enabled platforms a single clock
+ * 3) all clocks specified in the devicetree node, or a single
+ *    clock for non-OF platforms (optional)
  * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
  * 5) phys (optional)
  *
@@ -385,11 +367,10 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
 struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 						   unsigned int flags)
 {
+	int enabled_ports = 0, rc = 0, child_nodes;
 	struct device *dev = &pdev->dev;
 	struct ahci_host_priv *hpriv;
-	struct clk *clk;
 	struct device_node *child;
-	int i, enabled_ports = 0, rc = 0, child_nodes;
 	u32 mask_port_map = 0;
 
 	if (!devres_open_group(dev, NULL, GFP_KERNEL))
@@ -413,25 +394,32 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		}
 	}
 
-	for (i = 0; i < AHCI_MAX_CLKS; i++) {
-		/*
-		 * For now we must use clk_get(dev, NULL) for the first clock,
-		 * because some platforms (da850, spear13xx) are not yet
-		 * converted to use devicetree for clocks.  For new platforms
-		 * this is equivalent to of_clk_get(dev->of_node, 0).
-		 */
-		if (i == 0)
-			clk = clk_get(dev, NULL);
-		else
-			clk = of_clk_get(dev->of_node, i);
-
-		if (IS_ERR(clk)) {
-			rc = PTR_ERR(clk);
-			if (rc == -EPROBE_DEFER)
-				goto err_out;
-			break;
+	/*
+	 * Bulk clock get procedure can fail to find any clock due to running
+	 * an a non-OF platform or due to the clocks being defined in bypass
+	 * from the DT firmware (like da850, spear13xx). In that case we
+	 * fallback to getting a single clock source right from the dev clocks
+	 * list.
+	 */
+	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
+	if (rc > 0) {
+		hpriv->n_clks = rc;
+	} else if (!rc) {
+		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks), GFP_KERNEL);
+		if (!hpriv->clks) {
+			rc = -ENOMEM;
+			goto err_out;
 		}
-		hpriv->clks[i] = clk;
+		hpriv->clks->clk = devm_clk_get_optional(dev, NULL);
+		if (IS_ERR(hpriv->clks->clk)) {
+			rc = PTR_ERR(hpriv->clks->clk);
+			goto err_out;
+		} else if (hpriv->clks->clk) {
+			hpriv->clks->id = __clk_get_name(hpriv->clks->clk);
+			hpriv->n_clks = 1;
+		}
+	} else {
+		goto err_out;
 	}
 
 	hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
-- 
2.35.1


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

* [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (4 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  1:36   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number Serge Semin
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Since all the clocks are retrieved by the method
ahci_platform_get_resources() there is no need for the glue-drivers to be
looking for some particular of them in the kernel clocks table again.
Instead we suggest to add a simple method returning a device-specific
clock with passed connection ID if it is managed to be found. Otherwise
the function will return NULL. Thus the glue-drivers won't need to either
manually touching the hpriv->clks array or calling clk_get()-friends. The
AHCI platform drivers will be able to use the new function right after the
ahci_platform_get_resources() method invocation and up to the device
removal.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/libahci_platform.c | 27 +++++++++++++++++++++++++++
 include/linux/ahci_platform.h  |  3 +++
 2 files changed, 30 insertions(+)

diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index d805ddc3a024..4fb9629c03ab 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -94,6 +94,33 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
 }
 EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
 
+/**
+ * ahci_platform_find_clk - Find platform clock
+ * @hpriv: host private area to store config values
+ * @con_id: clock connection ID
+ *
+ * This function returns point to the clock descriptor of the clock with
+ * passed ID.
+ *
+ * RETURNS:
+ * Pointer to the clock descriptor on success otherwise NULL
+ */
+struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id)
+{
+	struct clk *clk = NULL;
+	int i;
+
+	for (i = 0; i < hpriv->n_clks; i++) {
+		if (!strcmp(hpriv->clks[i].id, con_id)) {
+			clk = hpriv->clks[i].clk;
+			break;
+		}
+	}
+
+	return clk;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_find_clk);
+
 /**
  * ahci_platform_enable_clks - Enable platform clocks
  * @hpriv: host private area to store config values
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 49e5383d4222..fd964e6a68d6 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -13,6 +13,7 @@
 
 #include <linux/compiler.h>
 
+struct clk;
 struct device;
 struct ata_port_info;
 struct ahci_host_priv;
@@ -21,6 +22,8 @@ struct scsi_host_template;
 
 int ahci_platform_enable_phys(struct ahci_host_priv *hpriv);
 void ahci_platform_disable_phys(struct ahci_host_priv *hpriv);
+struct clk *
+ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);
 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
 int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
-- 
2.35.1


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

* [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (5 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  1:40   ` Damien Le Moal
  2022-03-24  0:16   ` Serge Semin
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Having greater than (AHCI_MAX_PORTS = 32) ports detected isn't that
critical from the further AHCI-platform initialization point of view since
exceeding the ports upper limit will cause allocating more resources than
will be used afterwards. But detecting too many child DT-nodes doesn't
seem right since it's very unlikely to have it on an ordinary platform. In
accordance with the AHCI specification there can't be more than 32 ports
implemented at least due to having the CAP.NP field of 4 bits wide and the
PI register of dword size. Thus if such situation is found the DTB must
have been corrupted and the data read from it shouldn't be reliable. Let's
consider that as an erroneous situation and halt further resources
allocation.

Note it's logically more correct to have the nports set only after the
initialization value is checked for being sane. So while at it let's make
sure nports is assigned with a correct value.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/libahci_platform.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 4fb9629c03ab..845042295b97 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -470,15 +470,21 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		}
 	}
 
-	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
-
 	/*
-	 * If no sub-node was found, we still need to set nports to
-	 * one in order to be able to use the
+	 * Too many sub-nodes most likely means having something wrong with
+	 * firmware. If no sub-node was found, we still need to set nports
+	 * to one in order to be able to use the
 	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
 	 */
-	if (!child_nodes)
+	child_nodes = of_get_child_count(dev->of_node);
+	if (child_nodes > AHCI_MAX_PORTS) {
+		rc = -EINVAL;
+		goto err_out;
+	} else if (!child_nodes) {
 		hpriv->nports = 1;
+	} else {
+		hpriv->nports = child_nodes;
+	}
 
 	hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
 	if (!hpriv->phys) {
-- 
2.35.1


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

* [PATCH 08/21] ata: libahci_platform: Parse ports-implemented property in resources getter
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
  2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
@ 2022-03-24  0:16   ` Serge Semin
  2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
                     ` (19 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Matthias Brugger,
	Patrice Chotard
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek

The ports-implemented property is mainly used on the OF-based platforms
with no ports mapping initialized by a bootloader/BIOS firmware. Seeing
the same of_property_read_u32()-based pattern has already been implemented
in the generic AHCI glue driver and in the Mediatek, St AHCI drivers let's
move the property read procedure to the generic
ahci_platform_get_resources() method. Thus we'll have the forced ports
mapping feature supported for each OF-based platform which requires that,
and stop re-implementing the same pattern in there a bit simplifying the
code.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci_mtk.c         | 2 --
 drivers/ata/ahci_platform.c    | 3 ---
 drivers/ata/ahci_st.c          | 3 ---
 drivers/ata/libahci_platform.c | 3 +++
 4 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c
index d9b08ae7c3b2..8f8539952af1 100644
--- a/drivers/ata/ahci_mtk.c
+++ b/drivers/ata/ahci_mtk.c
@@ -118,8 +118,6 @@ static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
 				   SYS_CFG_SATA_EN);
 	}
 
-	of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map);
-
 	return 0;
 }
 
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 3aab2e3d57f3..24c25f076f37 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -56,9 +56,6 @@ static int ahci_probe(struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
 		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
 
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index c268264c2129..e010f2fd1fa2 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -168,9 +168,6 @@ static int st_ahci_probe(struct platform_device *pdev)
 
 	st_ahci_configure_oob(hpriv->mmio);
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
 				      &ahci_platform_sht);
 	if (err) {
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 845042295b97..5998e735a813 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -501,6 +501,9 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		goto err_out;
 	}
 
+	of_property_read_u32(dev->of_node,
+			     "ports-implemented", &hpriv->force_port_map);
+
 	if (child_nodes) {
 		for_each_child_of_node(dev->of_node, child) {
 			u32 port;
-- 
2.35.1


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

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

* [PATCH 08/21] ata: libahci_platform: Parse ports-implemented property in resources getter
@ 2022-03-24  0:16   ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Matthias Brugger,
	Patrice Chotard
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek

The ports-implemented property is mainly used on the OF-based platforms
with no ports mapping initialized by a bootloader/BIOS firmware. Seeing
the same of_property_read_u32()-based pattern has already been implemented
in the generic AHCI glue driver and in the Mediatek, St AHCI drivers let's
move the property read procedure to the generic
ahci_platform_get_resources() method. Thus we'll have the forced ports
mapping feature supported for each OF-based platform which requires that,
and stop re-implementing the same pattern in there a bit simplifying the
code.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci_mtk.c         | 2 --
 drivers/ata/ahci_platform.c    | 3 ---
 drivers/ata/ahci_st.c          | 3 ---
 drivers/ata/libahci_platform.c | 3 +++
 4 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c
index d9b08ae7c3b2..8f8539952af1 100644
--- a/drivers/ata/ahci_mtk.c
+++ b/drivers/ata/ahci_mtk.c
@@ -118,8 +118,6 @@ static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
 				   SYS_CFG_SATA_EN);
 	}
 
-	of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map);
-
 	return 0;
 }
 
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 3aab2e3d57f3..24c25f076f37 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -56,9 +56,6 @@ static int ahci_probe(struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
 		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
 
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index c268264c2129..e010f2fd1fa2 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -168,9 +168,6 @@ static int st_ahci_probe(struct platform_device *pdev)
 
 	st_ahci_configure_oob(hpriv->mmio);
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
 				      &ahci_platform_sht);
 	if (err) {
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 845042295b97..5998e735a813 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -501,6 +501,9 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		goto err_out;
 	}
 
+	of_property_read_u32(dev->of_node,
+			     "ports-implemented", &hpriv->force_port_map);
+
 	if (child_nodes) {
 		for_each_child_of_node(dev->of_node, child) {
 			u32 port;
-- 
2.35.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 08/21] ata: libahci_platform: Parse ports-implemented property in resources getter
@ 2022-03-24  0:16   ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Matthias Brugger,
	Patrice Chotard
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek

The ports-implemented property is mainly used on the OF-based platforms
with no ports mapping initialized by a bootloader/BIOS firmware. Seeing
the same of_property_read_u32()-based pattern has already been implemented
in the generic AHCI glue driver and in the Mediatek, St AHCI drivers let's
move the property read procedure to the generic
ahci_platform_get_resources() method. Thus we'll have the forced ports
mapping feature supported for each OF-based platform which requires that,
and stop re-implementing the same pattern in there a bit simplifying the
code.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci_mtk.c         | 2 --
 drivers/ata/ahci_platform.c    | 3 ---
 drivers/ata/ahci_st.c          | 3 ---
 drivers/ata/libahci_platform.c | 3 +++
 4 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c
index d9b08ae7c3b2..8f8539952af1 100644
--- a/drivers/ata/ahci_mtk.c
+++ b/drivers/ata/ahci_mtk.c
@@ -118,8 +118,6 @@ static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
 				   SYS_CFG_SATA_EN);
 	}
 
-	of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map);
-
 	return 0;
 }
 
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 3aab2e3d57f3..24c25f076f37 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -56,9 +56,6 @@ static int ahci_probe(struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
 		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
 
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index c268264c2129..e010f2fd1fa2 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -168,9 +168,6 @@ static int st_ahci_probe(struct platform_device *pdev)
 
 	st_ahci_configure_oob(hpriv->mmio);
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
-
 	err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
 				      &ahci_platform_sht);
 	if (err) {
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 845042295b97..5998e735a813 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -501,6 +501,9 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		goto err_out;
 	}
 
+	of_property_read_u32(dev->of_node,
+			     "ports-implemented", &hpriv->force_port_map);
+
 	if (child_nodes) {
 		for_each_child_of_node(dev->of_node, child) {
 			u32 port;
-- 
2.35.1


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

* [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (7 preceding siblings ...)
  2022-03-24  0:16   ` Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  1:52   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 10/21] dt-bindings: ata: ahci: Add platform capability properties Serge Semin
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Currently the ACHI-platform library supports only the assert and deassert
reset signals and ignores the platforms with self-deasserting reset lines.
That prone to having the platforms with self-deasserting reset method
misbehaviour when it comes to resuming from sleep state after the clocks
have been fully disabled. For such cases the controller needs to be fully
reset all over after the reference clocks are enabled and stable,
otherwise the controller state machine might be in an undetermined state.

The best solution would be to auto-detect which reset method is supported
by the particular platform and use it implicitly in the framework of the
ahci_platform_enable_resources()/ahci_platform_disable_resources()
methods. Alas it can't be implemented due to the AHCI-platform library
already supporting the shared reset control lines. As [1] says in such
case we have to use only one of the next methods:
+ reset_control_assert()/reset_control_deassert();
+ reset_control_reset()/reset_control_rearm().
If the driver had an exclusive control over the reset lines we could have
been able to manipulate the lines with no much limitation and just used
the combination of the methods above to cover all the possible
reset-control cases. Since the shared reset control has already been
advertised and couldn't be changed with no risk to breaking the platforms
relying on it, we have no choice but to make the platform drivers to
determine which reset methods the platform reset system supports.

In order to implement both types of reset control support we suggest to
introduce the new AHCI-platform flag: AHCI_PLATFORM_RST_TRIGGER, which
when passed to the ahci_platform_get_resources() method together with the
AHCI_PLATFORM_GET_RESETS flag will indicate that the reset lines are
self-deasserting thus the reset_control_reset()/reset_control_rearm() will
be used to control the reset state. Otherwise the
reset_control_deassert()/reset_control_assert() methods will be utilized.

[1] Documentation/driver-api/reset.rst

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.h             |  1 +
 drivers/ata/libahci_platform.c | 47 ++++++++++++++++++++++++++++++----
 include/linux/ahci_platform.h  |  5 +++-
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 1564c691094a..0b1d5c24cb8c 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -342,6 +342,7 @@ struct ahci_host_priv {
 	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
 	unsigned int		n_clks;
 	struct clk_bulk_data	*clks;		/* Optional */
+	unsigned int		f_rsts;
 	struct reset_control	*rsts;		/* Optional */
 	struct regulator	**target_pwrs;	/* Optional */
 	struct regulator	*ahci_regulator;/* Optional */
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 5998e735a813..febad33aa43c 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -150,6 +150,41 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
 }
 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
 
+/**
+ * ahci_platform_deassert_rsts - Deassert/trigger platform resets
+ * @hpriv: host private area to store config values
+ *
+ * This function desserts or triggers all the reset lanes found for the AHCI
+ * device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv)
+{
+	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
+		return reset_control_reset(hpriv->rsts);
+
+	return reset_control_deassert(hpriv->rsts);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_deassert_rsts);
+
+/**
+ * ahci_platform_assert_rsts - Assert/rearm platform resets
+ * @hpriv: host private area to store config values
+ *
+ * This function asserts or rearms (for self-deasserting resets) all the reset
+ * controls found for the AHCI device.
+ */
+void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv)
+{
+	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
+		return (void)reset_control_rearm(hpriv->rsts);
+
+	reset_control_assert(hpriv->rsts);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts);
+
 /**
  * ahci_platform_enable_regulators - Enable regulators
  * @hpriv: host private area to store config values
@@ -247,18 +282,18 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 	if (rc)
 		goto disable_regulator;
 
-	rc = reset_control_deassert(hpriv->rsts);
+	rc = ahci_platform_deassert_rsts(hpriv);
 	if (rc)
 		goto disable_clks;
 
 	rc = ahci_platform_enable_phys(hpriv);
 	if (rc)
-		goto disable_resets;
+		goto disable_rsts;
 
 	return 0;
 
-disable_resets:
-	reset_control_assert(hpriv->rsts);
+disable_rsts:
+	ahci_platform_assert_rsts(hpriv);
 
 disable_clks:
 	ahci_platform_disable_clks(hpriv);
@@ -285,7 +320,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
 {
 	ahci_platform_disable_phys(hpriv);
 
-	reset_control_assert(hpriv->rsts);
+	ahci_platform_assert_rsts(hpriv);
 
 	ahci_platform_disable_clks(hpriv);
 
@@ -468,6 +503,8 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 			rc = PTR_ERR(hpriv->rsts);
 			goto err_out;
 		}
+
+		hpriv->f_rsts = flags & AHCI_PLATFORM_RST_TRIGGER;
 	}
 
 	/*
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index fd964e6a68d6..57d25d30a9fa 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -26,6 +26,8 @@ struct clk *
 ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);
 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv);
+void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv);
 int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
 void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
 int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
@@ -44,6 +46,7 @@ int ahci_platform_resume_host(struct device *dev);
 int ahci_platform_suspend(struct device *dev);
 int ahci_platform_resume(struct device *dev);
 
-#define AHCI_PLATFORM_GET_RESETS	0x01
+#define AHCI_PLATFORM_GET_RESETS	BIT(0)
+#define AHCI_PLATFORM_RST_TRIGGER	BIT(1)
 
 #endif /* _AHCI_PLATFORM_H */
-- 
2.35.1


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

* [PATCH 10/21] dt-bindings: ata: ahci: Add platform capability properties
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (8 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 11/21] ata: libahci: Extend port-cmd flags set with port capabilities Serge Semin
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Rob Herring
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	linux-ide, linux-kernel, devicetree

In case if the platform doesn't have BIOS or a comprehensive firmware
installed then the HBA capability flags will be left uninitialized. As a
good alternative we can define a set AHCI DT-node properties to describe
all of HW-init capabilities flags. Luckily there aren't too many of them.
SSS - Staggered Spin-up support and MPS - Mechanical Presence Switch
support determine the corresponding feature availability for whole HBA by
means of the "hba-sss" and "hba-smps" properties.  Each port can have the
"hba-{hpcp,mpsp,cpd,esp,fbscp}" defined indicatating that the port
supports the next functionality: HPCP - HotPlug capable port, MPSP -
Mechanical Presence Switch attached to a port, CPD - Cold Plug detection,
ESP - External SATA Port (eSATA), FBSCP - FIS-based switching capable
port.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Alternatively we could define them as a bitfield, but having a set of
boolean properties seemed a better idea since in that case we can
implement a simple inter-dependency rules for them, which can't be done
should we take the bitfields path.
---
 .../devicetree/bindings/ata/ahci-common.yaml  | 66 +++++++++++++++++++
 .../devicetree/bindings/ata/generic-ahci.yaml |  9 +++
 2 files changed, 75 insertions(+)

diff --git a/Documentation/devicetree/bindings/ata/ahci-common.yaml b/Documentation/devicetree/bindings/ata/ahci-common.yaml
index 054819930538..1901c55a5468 100644
--- a/Documentation/devicetree/bindings/ata/ahci-common.yaml
+++ b/Documentation/devicetree/bindings/ata/ahci-common.yaml
@@ -67,6 +67,19 @@ properties:
   phy-names:
     const: sata-phy
 
+  hba-sss:
+    type: boolean
+    description:
+      Staggered Spin-up Support. Indicates whether the HBA supports the
+      staggered spin-up on its ports, for use in balancing power spikes.
+
+  hba-smps:
+    type: boolean
+    description:
+      Mechanical Presence Switch Support. Indicates whether the HBA supports
+      mechanical presence switches on its ports for use in hot plug
+      operations.
+
   ports-implemented:
     $ref: /schemas/types.yaml#/definitions/uint32
     description:
@@ -88,6 +101,40 @@ patternProperties:
         minimum: 0
         maximum: 31
 
+      hba-hpcp:
+        type: boolean
+        description:
+          Hot Plug Capable Port. Indicates that this port’s signal and power
+          connectors are externally accessible via a joint signal and power
+          connector for blindmate device hot plug. It is mutually exclusive
+          with the ESP feature.
+
+      hba-mpsp:
+        type: boolean
+        description:
+          Mechanical Presence Switch Attached to Port. Indicates whether
+          the platform an mechanical presence switch attached to this
+          port.
+
+      hba-cpd:
+        type: boolean
+        description:
+          Cold Presence Detection. Indicates whether the platform supports
+          cold presence detection on this port.
+
+      hba-esp:
+        type: boolean
+        description:
+          External SATA Port. Indicates that this port’s signal connector
+          is externally accessible on a signal only connector (e.g. eSATA
+          connector).
+
+      hba-fbscp:
+        type: boolean
+        description:
+          FIS-based Switching Capable Port. Indicates whether this port
+          supports Port Multiplier FIS-based switching.
+
       phys:
         description: Individual AHCI SATA port PHY
         maxItems: 1
@@ -101,6 +148,25 @@ patternProperties:
     required:
       - reg
 
+    # eSATA can't be enabled together with the HotPlug capability
+    oneOf:
+      - required:
+          - hba-hpcp
+      - required:
+          - hba-esp
+      - not:
+          anyOf:
+            - required:
+                - hba-hpcp
+            - required:
+                - hba-esp
+
+    # HotPlug capability must be enabled together with Cold Plug
+    # Detection and Mechanical Presence Switching.
+    dependencies:
+      hba-cpd: ["hba-hpcp"]
+      hba-mpsp: ["hba-hpcp"]
+
 required:
   - reg
   - interrupts
diff --git a/Documentation/devicetree/bindings/ata/generic-ahci.yaml b/Documentation/devicetree/bindings/ata/generic-ahci.yaml
index 957f45c4f488..6c147350b5f9 100644
--- a/Documentation/devicetree/bindings/ata/generic-ahci.yaml
+++ b/Documentation/devicetree/bindings/ata/generic-ahci.yaml
@@ -74,14 +74,23 @@ examples:
 
       interrupts = <GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>;
 
+      hba-smps;
+
       sata-port@0 {
         reg = <0>;
+
+        hba-fbscp;
+        hba-esp;
         phys = <&sata_phy0>;
         phy-names = "sata-phy";
       };
 
       sata-port@1 {
         reg = <1>;
+
+        hba-fbscp;
+        hba-hpcp;
+        hba-mpsp;
         phys = <&sata_phy1>;
         phy-names = "sata-phy";
       };
-- 
2.35.1


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

* [PATCH 11/21] ata: libahci: Extend port-cmd flags set with port capabilities
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (9 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 10/21] dt-bindings: ata: ahci: Add platform capability properties Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter Serge Semin
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Currently not all of the Port-specific capabilities listed in the
PORT_CMD-enumeration. Let's extend that set with the Cold Presence
Detection and Mechanical Presence Switch attached to the Port flags [1] so
to closeup the set of the platform-specific port-capabilities flags.  Note
these flags are supposed to be set by the platform firmware if there is
one. Alternatively as we are about to do they can be set by means of the
OF properties.

While at it replace PORT_IRQ_DEV_ILCK with PORT_IRQ_DEV_MPS and fix the
comment there. In accordance with [2] that IRQ flag is supposed to
indicate the state of the signal coming from the Mechanical Presence
Switch.

[1] Serial ATA AHCI 1.3.1 Specification, p.27
[2] Serial ATA AHCI 1.3.1 Specification, p.7

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 0b1d5c24cb8c..04690b4168a3 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -138,7 +138,7 @@ enum {
 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
 
 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
-	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
+	PORT_IRQ_DMPS		= (1 << 7), /* mechanical presence status */
 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
@@ -166,6 +166,8 @@ enum {
 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
 	PORT_CMD_FBSCP		= (1 << 22), /* FBS Capable Port */
 	PORT_CMD_ESP		= (1 << 21), /* External Sata Port */
+	PORT_CMD_CPD		= (1 << 20), /* Cold Presence Detection */
+	PORT_CMD_MPSP		= (1 << 19), /* Mechanical Presence Switch */
 	PORT_CMD_HPCP		= (1 << 18), /* HotPlug Capable Port */
 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
@@ -181,6 +183,9 @@ enum {
 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
 
+	PORT_CMD_CAP		= PORT_CMD_HPCP | PORT_CMD_MPSP |
+				  PORT_CMD_CPD | PORT_CMD_ESP | PORT_CMD_FBSCP,
+
 	/* PORT_FBS bits */
 	PORT_FBS_DWE_OFFSET	= 16, /* FBS device with error offset */
 	PORT_FBS_ADO_OFFSET	= 12, /* FBS active dev optimization offset */
-- 
2.35.1


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

* [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (10 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 11/21] ata: libahci: Extend port-cmd flags set with port capabilities Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  2:05   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 13/21] ata: libahci: Don't read AHCI version twice in the save-config method Serge Semin
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Currently there are four port-map-related fields declared in the
ahci_host_priv structure and used to setup the HBA ports mapping. First
the ports-mapping is read from the PI register and immediately stored in
the saved_port_map field. If forced_port_map is initialized with non-zero
value then its value will have greater priority over the value read from
PI, thus it will override the saved_port_map field. That value will be then
masked by a non-zero mask_port_map field and after some sanity checks it
will be stored in the ahci_host_priv.port_map field as a final port
mapping.

As you can see the logic is a bit too complicated for such a simple task.
We can freely get rid from at least one of the fields with no change to
the implemented semantic. The force_port_map field can be replaced with
taking non-zero saved_port_map value into account. So if saved_port_map is
pre-initialized by the glue-driver/platform-specific code then it will
have greater priority over the value read from PI register and will be
used as actual HBA ports mapping later on. Thus the ports map forcing task
will be just transferred from the force_port_map to saved_port_map field.

This modification will perfectly fit into the feature of having OF-based
initialization of the HW-init HBA CSR fields we are about to introduce in
the next commit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.c             |  2 +-
 drivers/ata/ahci.h             |  1 -
 drivers/ata/libahci.c          | 10 ++++++----
 drivers/ata/libahci_platform.c |  2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index ab5811ef5a53..8ce0d166cc8d 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -654,7 +654,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
 {
 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
 		dev_info(&pdev->dev, "JMB361 has only one port\n");
-		hpriv->force_port_map = 1;
+		hpriv->saved_port_map = 1;
 	}
 
 	/*
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 04690b4168a3..519d148ecaea 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -329,7 +329,6 @@ struct ahci_port_priv {
 struct ahci_host_priv {
 	/* Input fields */
 	unsigned int		flags;		/* AHCI_HFLAG_* */
-	u32			force_port_map;	/* force port map */
 	u32			mask_port_map;	/* mask out particular bits */
 
 	void __iomem *		mmio;		/* bus-independent mem map */
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 0ed484e04fd6..011175e82174 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -453,7 +453,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 	 * reset.  Values without are used for driver operation.
 	 */
 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
-	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
 	/* CAP2 register is only defined for AHCI 1.2 and later */
 	vers = readl(mmio + HOST_VERSION);
@@ -517,10 +516,13 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 		cap &= ~HOST_CAP_SXS;
 	}
 
-	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
+	/* Override the HBA ports mapping if the platform needs it */
+	port_map = readl(mmio + HOST_PORTS_IMPL);
+	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
 		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
-			 port_map, hpriv->force_port_map);
-		port_map = hpriv->force_port_map;
+			 port_map, hpriv->saved_port_map);
+		port_map = hpriv->saved_port_map;
+	} else {
 		hpriv->saved_port_map = port_map;
 	}
 
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index febad33aa43c..5cbc2c42164d 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -539,7 +539,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 	}
 
 	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->force_port_map);
+			     "ports-implemented", &hpriv->saved_port_map);
 
 	if (child_nodes) {
 		for_each_child_of_node(dev->of_node, child) {
-- 
2.35.1


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

* [PATCH 13/21] ata: libahci: Don't read AHCI version twice in the save-config method
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (11 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 14/21] ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments Serge Semin
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

There is no point in reading the AHCI version all over in the tail of the
ahci_save_initial_config() method. That register is RO and doesn't change
its value even after reset. So just reuse the data, which has already been
read from there earlier in the head of the function.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/libahci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 011175e82174..43460da06947 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -564,7 +564,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 	/* record values to use during operation */
 	hpriv->cap = cap;
 	hpriv->cap2 = cap2;
-	hpriv->version = readl(mmio + HOST_VERSION);
+	hpriv->version = vers;
 	hpriv->port_map = port_map;
 
 	if (!hpriv->start_engine)
-- 
2.35.1


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

* [PATCH 14/21] ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (12 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 13/21] ata: libahci: Don't read AHCI version twice in the save-config method Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 15/21] ata: ahci: Introduce firmware-specific caps initialization Serge Semin
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

It may get required to retrieve the port-base address even before the
ata_host instance is initialized and activated, for instance in the
ahci_save_initial_config() method which we about to update (consider this
modification as a preparation for that one). Seeing the __ahci_port_base()
function isn't used much it's the best candidate to provide the required
functionality. So let's convert it to accepting the ahci_host_priv
structure pointer.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.c | 2 +-
 drivers/ata/ahci.h | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 8ce0d166cc8d..973190732cd6 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -687,7 +687,7 @@ static void ahci_pci_init_controller(struct ata_host *host)
 			mv = 2;
 		else
 			mv = 4;
-		port_mmio = __ahci_port_base(host, mv);
+		port_mmio = __ahci_port_base(hpriv, mv);
 
 		writel(0, port_mmio + PORT_IRQ_MASK);
 
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 519d148ecaea..0fde57e7457e 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -433,10 +433,9 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
 void ahci_error_handler(struct ata_port *ap);
 u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
 
-static inline void __iomem *__ahci_port_base(struct ata_host *host,
+static inline void __iomem *__ahci_port_base(struct ahci_host_priv *hpriv,
 					     unsigned int port_no)
 {
-	struct ahci_host_priv *hpriv = host->private_data;
 	void __iomem *mmio = hpriv->mmio;
 
 	return mmio + 0x100 + (port_no * 0x80);
@@ -444,7 +443,9 @@ static inline void __iomem *__ahci_port_base(struct ata_host *host,
 
 static inline void __iomem *ahci_port_base(struct ata_port *ap)
 {
-	return __ahci_port_base(ap->host, ap->port_no);
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+
+	return __ahci_port_base(hpriv, ap->port_no);
 }
 
 static inline int ahci_nr_ports(u32 cap)
-- 
2.35.1


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

* [PATCH 15/21] ata: ahci: Introduce firmware-specific caps initialization
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (13 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 14/21] ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema Serge Semin
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

There are systems with no BIOS or comprehensive embedded firmware which
could be able to properly initialize the SATA AHCI controller
platform-specific capabilities. In that case a good alternative to having
a clever bootloader is to create a device tree node with the properties
well describing all the AHCI-related platform specifics. All the settings
which are normally detected and marked as available in the HBA and its
ports capabilities fields [1] could be defined in the platform DTB by
means of a set of the dedicated properties. Such approach perfectly fits
to the DTB-philosophy - to provide hardware/platform description.

So here we suggest to extend the SATA AHCI device tree bindings with the
next set of additional DT boolean properties:
1) hba-sss - Controller supports Staggered Spin-up.
2) hba-smps - Mechanical Presence Switch is support by controller.
3) hba-hpcp - Hot Plug Capable Port.
4) hba-mpsp - Mechanical Presence Switch Attached to Port.
5) hba-cpd - Cold Presence Detection.
6) hba-esp - External SATA Port.
7) hba-fbscp - FIS-based Switching Capable Port.
All of these capabilities require to have a corresponding hardware
configuration. Thus it's ok to have them defined in DTB.

Even though the driver currently takes into account the state of the ESP
and FBSCP flags state only, there is nothing wrong with having all them
supported by the generic AHCI library in order to have a complete OF-based
platform-capabilities initialization procedure. These properties will be
parsed in the ahci_platform_get_resources() method and their values will
be stored in the saved_* fields of the ahci_host_priv structure, which in
its turn then will be used to restore the H.CAP, H.PI and P#.CMD
capability fields on device init and after HBA reset.

Please note this modification concerns the HW-init HBA and its ports flags
only, which are by specification [1] are supposed to be initialized by the
BIOS/platform firmware/expansion ROM and which are normally declared in
the one-time-writable-after-reset register fields. Even though these flags
aren't supposed to be cleared after HBA reset some AHCI instances may
violate that rule so we still need to perform the fields resetting after
each reset. Luckily the corresponding functionality has already been
partly implemented in the framework of the ahci_save_initial_config() and
ahci_restore_initial_config() methods.

[1] Serial ATA AHCI 1.3.1 Specification, p. 103

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci.h             |  1 +
 drivers/ata/libahci.c          | 51 ++++++++++++++++++++++++++++------
 drivers/ata/libahci_platform.c | 51 ++++++++++++++++++++++++++++++++--
 3 files changed, 92 insertions(+), 11 deletions(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 0fde57e7457e..35eaa42e9269 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -339,6 +339,7 @@ struct ahci_host_priv {
 	u32			saved_cap;	/* saved initial cap */
 	u32			saved_cap2;	/* saved initial cap2 */
 	u32			saved_port_map;	/* saved initial port_map */
+	u32			saved_port_cap[AHCI_MAX_PORTS]; /* saved port_cap */
 	u32 			em_loc; /* enclosure management location */
 	u32			em_buf_sz;	/* EM buffer size in byte */
 	u32			em_msg_type;	/* EM message type */
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 43460da06947..9e67c90900d2 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -16,6 +16,7 @@
  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
  */
 
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
@@ -443,16 +444,28 @@ static ssize_t ahci_show_em_supported(struct device *dev,
 void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 {
 	void __iomem *mmio = hpriv->mmio;
-	u32 cap, cap2, vers, port_map;
+	void __iomem *port_mmio;
+	unsigned long port_map;
+	u32 cap, cap2, vers;
 	int i;
 
 	/* make sure AHCI mode is enabled before accessing CAP */
 	ahci_enable_ahci(mmio);
 
-	/* Values prefixed with saved_ are written back to host after
-	 * reset.  Values without are used for driver operation.
+	/*
+	 * Values prefixed with saved_ are written back to the HBA and ports
+	 * registers after reset. Values without are used for driver operation.
+	 */
+
+	/*
+	 * Override HW-init HBA capability fields with platform-specific values.
+	 * The rest of the HBA capabilities are defined with strictly RO flags
+	 * and can't be modified in CSR anyway.
 	 */
-	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+	cap = readl(mmio + HOST_CAP);
+	if (hpriv->saved_cap)
+		cap = (cap & ~(HOST_CAP_SSS | HOST_CAP_MPS)) | hpriv->saved_cap;
+	hpriv->saved_cap = cap;
 
 	/* CAP2 register is only defined for AHCI 1.2 and later */
 	vers = readl(mmio + HOST_VERSION);
@@ -519,7 +532,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 	/* Override the HBA ports mapping if the platform needs it */
 	port_map = readl(mmio + HOST_PORTS_IMPL);
 	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
-		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
+		dev_info(dev, "forcing port_map 0x%lx -> 0x%x\n",
 			 port_map, hpriv->saved_port_map);
 		port_map = hpriv->saved_port_map;
 	} else {
@@ -527,7 +540,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 	}
 
 	if (hpriv->mask_port_map) {
-		dev_warn(dev, "masking port_map 0x%x -> 0x%x\n",
+		dev_warn(dev, "masking port_map 0x%lx -> 0x%lx\n",
 			port_map,
 			port_map & hpriv->mask_port_map);
 		port_map &= hpriv->mask_port_map;
@@ -546,7 +559,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 		 */
 		if (map_ports > ahci_nr_ports(cap)) {
 			dev_warn(dev,
-				 "implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n",
+				 "implemented port map (0x%lx) contains more ports than nr_ports (%u), using nr_ports\n",
 				 port_map, ahci_nr_ports(cap));
 			port_map = 0;
 		}
@@ -555,12 +568,26 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 	/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
 	if (!port_map && vers < 0x10300) {
 		port_map = (1 << ahci_nr_ports(cap)) - 1;
-		dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
+		dev_warn(dev, "forcing PORTS_IMPL to 0x%lx\n", port_map);
 
 		/* write the fixed up value to the PI register */
 		hpriv->saved_port_map = port_map;
 	}
 
+	/*
+	 * Preserve the ports capabilities defined by the platform. Note there
+	 * is no need in storing the rest of the P#.CMD fields since they are
+	 * volatile.
+	 */
+	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
+		if (hpriv->saved_port_cap[i])
+			continue;
+
+		port_mmio = __ahci_port_base(hpriv, i);
+		hpriv->saved_port_cap[i] =
+			readl(port_mmio + PORT_CMD) & PORT_CMD_CAP;
+	}
+
 	/* record values to use during operation */
 	hpriv->cap = cap;
 	hpriv->cap2 = cap2;
@@ -590,13 +617,21 @@ EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 static void ahci_restore_initial_config(struct ata_host *host)
 {
 	struct ahci_host_priv *hpriv = host->private_data;
+	unsigned long port_map = hpriv->port_map;
 	void __iomem *mmio = hpriv->mmio;
+	void __iomem *port_mmio;
+	int i;
 
 	writel(hpriv->saved_cap, mmio + HOST_CAP);
 	if (hpriv->saved_cap2)
 		writel(hpriv->saved_cap2, mmio + HOST_CAP2);
 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
+
+	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
+		port_mmio = __ahci_port_base(hpriv, i);
+		writel(hpriv->saved_port_cap[i], port_mmio + PORT_CMD);
+	}
 }
 
 static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 5cbc2c42164d..493144716c6e 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -23,6 +23,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/of_platform.h>
 #include <linux/reset.h>
+
 #include "ahci.h"
 
 static void ahci_host_stop(struct ata_host *host);
@@ -407,6 +408,44 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
 	return rc;
 }
 
+static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
+				      struct device *dev)
+{
+	struct device_node *child;
+	u32 port;
+
+	of_property_read_u32(dev->of_node,
+			     "ports-implemented", &hpriv->saved_port_map);
+
+	if (of_property_read_bool(dev->of_node, "hba-sss"))
+		hpriv->saved_cap |= HOST_CAP_SSS;
+	if (of_property_read_bool(dev->of_node, "hba-smps"))
+		hpriv->saved_cap |= HOST_CAP_MPS;
+
+	for_each_child_of_node(dev->of_node, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		if (of_property_read_u32(child, "reg", &port)) {
+			of_node_put(child);
+			return -EINVAL;
+		}
+
+		if (of_property_read_bool(child, "hba-hpcp"))
+			hpriv->saved_port_cap[port] |= PORT_CMD_HPCP;
+		if (of_property_read_bool(child, "hba-mpsp"))
+			hpriv->saved_port_cap[port] |= PORT_CMD_MPSP;
+		if (of_property_read_bool(child, "hba-cpd"))
+			hpriv->saved_port_cap[port] |= PORT_CMD_CPD;
+		if (of_property_read_bool(child, "hba-esp"))
+			hpriv->saved_port_cap[port] |= PORT_CMD_ESP;
+		if (of_property_read_bool(child, "hba-fbscp"))
+			hpriv->saved_port_cap[port] |= PORT_CMD_FBSCP;
+	}
+
+	return 0;
+}
+
 /**
  * ahci_platform_get_resources - Get platform resources
  * @pdev: platform device to get resources for
@@ -538,9 +577,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		goto err_out;
 	}
 
-	of_property_read_u32(dev->of_node,
-			     "ports-implemented", &hpriv->saved_port_map);
-
 	if (child_nodes) {
 		for_each_child_of_node(dev->of_node, child) {
 			u32 port;
@@ -605,6 +641,15 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
 		if (rc == -EPROBE_DEFER)
 			goto err_out;
 	}
+
+	/*
+	 * Retrieve firmware-specific flags which then will be used to set
+	 * the HW-init fields of HBA and its ports
+	 */
+	rc = ahci_platform_get_firmware(hpriv, dev);
+	if (rc)
+		goto err_out;
+
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	hpriv->got_runtime_pm = true;
-- 
2.35.1


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

* [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (14 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 15/21] ata: ahci: Introduce firmware-specific caps initialization Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-04-01  0:06   ` Rob Herring
  2022-03-24  0:16 ` [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support Serge Semin
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin, Rob Herring
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, linux-ide,
	linux-kernel, devicetree

Synopsys AHCI SATA controller is mainly compatible with the generic AHCI
SATA controller except a few peculiarities and the platform environment
requirements. In particular it can have one or two reference clocks to
feed up its AXI/AHB interface and SATA PHYs domain and at least one reset
control for the application clock domain. In addition to that the DMA
interface of each port can be tuned up to work with the predefined maximum
data chunk size. Note unlike generic AHCI controller DWC AHCI can't have
more than 8 ports. All of that is reflected in the new DWC AHCI SATA
device DT binding.

Note the DWC AHCI SATA controller DT-schema has been created in a way so
to be reused for the vendor-specific DT-schemas. One of which we are about
to introduce.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml

diff --git a/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
new file mode 100644
index 000000000000..b443154b63aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ata/snps,dwc-ahci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DWC AHCI SATA controller
+
+maintainers:
+  - Serge Semin <fancer.lancer@gmail.com>
+
+description: |
+  This document defines device tree bindings for the Synopsys DWC
+  implementation of the AHCI SATA controller.
+
+allOf:
+  - $ref: ahci-common.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - description: Synopsys AHCI SATA-compatible devices
+        contains:
+          const: snps,dwc-ahci
+      - description: SPEAr1340 AHCI SATA device
+        const: snps,spear-ahci
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description:
+      Basic DWC AHCI SATA clock sources like application AXI/AHB BIU clock
+      and embedded PHYs reference clock together with vendor-specific set
+      of clocks.
+    minItems: 1
+    maxItems: 4
+
+  clock-names:
+    contains:
+      anyOf:
+        - description: Application AXI/AHB BIU clock source
+          enum:
+            - aclk
+            - sata
+        - description: SATA Ports reference clock
+          enum:
+            - ref
+            - sata_ref
+
+  resets:
+    description:
+      At least basic core and application clock domains reset is normally
+      supported by the DWC AHCI SATA controller. Some platform specific
+      clocks can be also specified though.
+
+  reset-names:
+    contains:
+      description: Core and application clock domains reset control
+      const: arst
+
+patternProperties:
+  "^sata-port@[0-9a-e]$":
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 7
+
+      snps,tx-ts-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Maximal size of Tx DMA transactions in FIFO words
+        minimum: 1
+        maximum: 1024
+
+      snps,rx-ts-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Maximal size of Rx DMA transactions in FIFO words
+        minimum: 1
+        maximum: 1024
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    sata@122f0000 {
+      compatible = "snps,dwc-ahci";
+      reg = <0x122F0000 0x1ff>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+
+      clocks = <&clock1>, <&clock2>;
+      clock-names = "aclk", "ref";
+
+      phys = <&sata_phy>;
+      phy-names = "sata-phy";
+
+      ports-implemented = <0x1>;
+
+      sata-port@0 {
+        reg = <0>;
+
+        hba-fbscp;
+        snps,tx-ts-max = <512>;
+        snps,tx-rs-max = <512>;
+      };
+    };
+...
-- 
2.35.1


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

* [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (15 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  2:21   ` Damien Le Moal
  2022-03-24  0:16 ` [PATCH 18/21] dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema Serge Semin
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

Synopsys AHCI SATA controller can work pretty under with the generic
AHCI-platform driver control. But there are vendor-specific peculiarities
which can tune the device performance up and which may need to be fixed up
for proper device functioning. In addition some DWC AHCI-based controllers
may require small platform-specific fixups, so adding them in the generic
AHCI driver would have ruined the code simplicity. Shortly speaking in
order to keep the generic AHCI-platform code clean and have DWC AHCI
SATA-specific features supported we suggest to add a dedicated DWC AHCI
SATA device driver. Aside with the standard AHCI-platform resources
getting, enabling/disabling and the controller registration the new driver
performs the next actions.

First of all there is a way to verify whether the HBA/ports capabilities
activated in OF are correct. Almost all features availability is reflected
in the vendor-specific parameters registers. So the DWC AHCI driver does
the capabilities sanity check based on the corresponding fields state.

Secondly if either the Command Completion Coalescing or the Device Sleep
feature is enabled the DWC AHCI-specific internal 1ms timer must be fixed
in accordance with the application clock signal frequency. In particular
the timer value must be set to be Fapp * 1000. Normally the SoC designers
pre-configure the TIMER1MS register to contain a correct value by default.
But the platforms can support the application clock rate change. If that
happens the 1ms timer value must be accordingly updated otherwise the
dependent features won't work as expected. In the DWC AHCI driver we
suggest to rely on the "aclk" reference clock rate to set the timer
interval up. That clock source is supposed to be the AHCI SATA application
clock in accordance with the DT bindings.

Finally DWC AHCI SATA controller AXI/AHB bus DMA-engine can be tuned up to
transfer up to 1024 * FIFO words at a time by setting the Tx/Rx
transaction size in the DMA control register. The maximum value depends on
the DMA data bus and AXI/AHB bus maximum burst length. In most of the
cases it's better to set the maximum possible value to reach the best AHCI
SATA controller performance. But sometimes in order to improve the system
interconnect responsiveness, transferring in smaller data chunks may be
more preferable. For such cases and for the case when the default value
doesn't provide the best DMA bus performance we suggest to use the new
HBA-port specific DT-properties "snps,{tx,rx}-ts-max" to tune the DMA
transactions size up.

After all the settings denoted above are handled the DWC AHCI SATA driver
proceeds further with the standard AHCI-platform host initializations.

Note since DWC AHCI controller is now have a dedicated driver we can
discard the corresponding compatible string from the ahci-platform.c
module. The same concerns "snps,spear-ahci" compatible string, which is
also based on the DWC AHCI IP-core.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Note there are three more AHCI SATA drivers which have been created for
the devices based on the DWC AHCI SATA IP-core. It's AHCI SunXi, St and
iMX drivers. Mostly they don't support the features implemented in this
driver. So hopefully sometime in future they can be converted to be based
on the generic DWC AHCI SATA driver and just perform some
subvendor-specific setups in their own glue-driver code. But for now
let's leave the generic DWC AHCI SATA code as is. Hopefully the new DWC
AHCI-based device drivers will try at least to re-use a part of the DWC
AHCI driver methods if not being able to be integrated in the generic
DWC driver code.
---
 drivers/ata/Kconfig         |  10 +
 drivers/ata/Makefile        |   1 +
 drivers/ata/ahci_dwc.c      | 395 ++++++++++++++++++++++++++++++++++++
 drivers/ata/ahci_platform.c |   2 -
 4 files changed, 406 insertions(+), 2 deletions(-)
 create mode 100644 drivers/ata/ahci_dwc.c

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index cb54631fd950..ab11bcf8510c 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -174,6 +174,16 @@ config AHCI_DM816
 
 	  If unsure, say N.
 
+config AHCI_DWC
+	tristate "Synopsys DWC AHCI SATA support"
+	select SATA_HOST
+	default SATA_AHCI_PLATFORM
+	help
+	  This option enables support for the Synopsys DWC AHCI SATA
+	  controller implementation.
+
+	  If unsure, say N.
+
 config AHCI_ST
 	tristate "ST AHCI SATA support"
 	depends on ARCH_STI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index b8aebfb14e82..34623365d9a6 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_DM816)	+= ahci_dm816.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_DWC)		+= ahci_dwc.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_IMX)		+= ahci_imx.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_MTK)		+= ahci_mtk.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_MVEBU)	+= ahci_mvebu.o libahci.o libahci_platform.o
diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
new file mode 100644
index 000000000000..c51e2251994e
--- /dev/null
+++ b/drivers/ata/ahci_dwc.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DWC AHCI SATA Platform driver
+ *
+ * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include "ahci.h"
+
+#define DRV_NAME "ahci-dwc"
+
+#define DWC_AHCI_FBS_PMPN_MAX		15
+
+/* DWC AHCI SATA controller specific registers */
+#define DWC_AHCI_HOST_OOBR		0xbc
+#define DWC_AHCI_HOST_OOB_WE		BIT(31)
+#define DWC_AHCI_HOST_CWMIN_MASK	GENMASK(30, 24)
+#define DWC_AHCI_HOST_CWMAX_MASK	GENMASK(23, 16)
+#define DWC_AHCI_HOST_CIMIN_MASK	GENMASK(15, 8)
+#define DWC_AHCI_HOST_CIMAX_MASK	GENMASK(7, 0)
+
+#define DWC_AHCI_HOST_GPCR		0xd0
+#define DWC_AHCI_HOST_GPSR		0xd4
+
+#define DWC_AHCI_HOST_TIMER1MS		0xe0
+#define DWC_AHCI_HOST_TIMV_MASK		GENMASK(19, 0)
+
+#define DWC_AHCI_HOST_GPARAM1R		0xe8
+#define DWC_AHCI_HOST_ALIGN_M		BIT(31)
+#define DWC_AHCI_HOST_RX_BUFFER		BIT(30)
+#define DWC_AHCI_HOST_PHY_DATA_MASK	GENMASK(29, 28)
+#define DWC_AHCI_HOST_PHY_RST		BIT(27)
+#define DWC_AHCI_HOST_PHY_CTRL_MASK	GENMASK(26, 21)
+#define DWC_AHCI_HOST_PHY_STAT_MASK	GENMASK(20, 15)
+#define DWC_AHCI_HOST_LATCH_M		BIT(14)
+#define DWC_AHCI_HOST_PHY_TYPE_MASK	GENMASK(13, 11)
+#define DWC_AHCI_HOST_RET_ERR		BIT(10)
+#define DWC_AHCI_HOST_AHB_ENDIAN_MASK	GENMASK(9, 8)
+#define DWC_AHCI_HOST_S_HADDR		BIT(7)
+#define DWC_AHCI_HOST_M_HADDR		BIT(6)
+#define DWC_AHCI_HOST_S_HDATA_MASK	GENMASK(5, 3)
+#define DWC_AHCI_HOST_M_HDATA_MASK	GENMASK(2, 0)
+
+#define DWC_AHCI_HOST_GPARAM2R		0xec
+#define DWC_AHCI_HOST_FBS_MEM_S		BIT(19)
+#define DWC_AHCI_HOST_FBS_PMPN_MASK	GENMASK(17, 16)
+#define DWC_AHCI_HOST_FBS_SUP		BIT(15)
+#define DWC_AHCI_HOST_DEV_CP		BIT(14)
+#define DWC_AHCI_HOST_DEV_MP		BIT(13)
+#define DWC_AHCI_HOST_ENCODE_M		BIT(12)
+#define DWC_AHCI_HOST_RXOOB_CLK_M	BIT(11)
+#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
+#define DWC_AHCI_HOST_TXOOB_M		BIT(9)
+#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
+#define DWC_AHCI_HOST_RXOOB_CLK_MASK	GENMASK(8, 0)
+
+#define DWC_AHCI_HOST_PPARAMR		0xf0
+#define DWC_AHCI_HOST_TX_MEM_M		BIT(11)
+#define DWC_AHCI_HOST_TX_MEM_S		BIT(10)
+#define DWC_AHCI_HOST_RX_MEM_M		BIT(9)
+#define DWC_AHCI_HOST_RX_MEM_S		BIT(8)
+#define DWC_AHCI_HOST_TXFIFO_DEPTH	GENMASK(7, 4)
+#define DWC_AHCI_HOST_RXFIFO_DEPTH	GENMASK(3, 0)
+
+#define DWC_AHCI_HOST_TESTR		0xf4
+#define DWC_AHCI_HOST_PSEL_MASK		GENMASK(18, 16)
+#define DWC_AHCI_HOST_TEST_IF		BIT(0)
+
+#define DWC_AHCI_HOST_VERSIONR		0xf8
+#define DWC_AHCI_HOST_IDR		0xfc
+
+#define DWC_AHCI_PORT_DMACR		0x70
+#define DWC_AHCI_PORT_RXABL_MASK	GENMASK(15, 12)
+#define DWC_AHCI_PORT_TXABL_MASK	GENMASK(11, 8)
+#define DWC_AHCI_PORT_RXTS_MASK		GENMASK(7, 4)
+#define DWC_AHCI_PORT_TXTS_MASK		GENMASK(3, 0)
+#define DWC_AHCI_PORT_PHYCR		0x74
+#define DWC_AHCI_PORT_PHYSR		0x78
+
+struct dwc_ahci_host_priv {
+	struct platform_device *pdev;
+
+	u32 timv;
+	u32 dmacr[AHCI_MAX_PORTS];
+};
+
+static struct ahci_host_priv *dwc_ahci_get_resources(struct platform_device *pdev)
+{
+	struct dwc_ahci_host_priv *dpriv;
+	struct ahci_host_priv *hpriv;
+
+	dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);
+	if (!dpriv)
+		return ERR_PTR(-ENOMEM);
+
+	dpriv->pdev = pdev;
+
+	hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
+	if (IS_ERR(hpriv))
+		return hpriv;
+
+	hpriv->plat_data = (void *)dpriv;
+
+	return hpriv;
+}
+
+static void dwc_ahci_check_cap(struct ahci_host_priv *hpriv)
+{
+	unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+	bool dev_mp, dev_cp, fbs_sup;
+	unsigned int fbs_pmp;
+	u32 param;
+	int i;
+
+	param = readl(hpriv->mmio + DWC_AHCI_HOST_GPARAM2R);
+	dev_mp = !!(param & DWC_AHCI_HOST_DEV_MP);
+	dev_cp = !!(param & DWC_AHCI_HOST_DEV_CP);
+	fbs_sup = !!(param & DWC_AHCI_HOST_FBS_SUP);
+	fbs_pmp = 5 * FIELD_GET(DWC_AHCI_HOST_FBS_PMPN_MASK, param);
+
+	if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {
+		dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");
+		hpriv->saved_cap &= ~HOST_CAP_MPS;
+	}
+
+
+	if (fbs_sup && fbs_pmp < DWC_AHCI_FBS_PMPN_MAX) {
+		dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",
+			 fbs_pmp);
+	}
+
+	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
+		if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {
+			dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);
+			hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;
+		}
+
+		if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {
+			dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);
+			hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;
+		}
+
+		if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {
+			dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);
+			hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;
+		}
+	}
+}
+
+static void dwc_ahci_init_timer(struct ahci_host_priv *hpriv)
+{
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+	unsigned long rate;
+	struct clk *aclk;
+	u32 cap, cap2;
+
+	/* 1ms tick is generated only for the CCC or DevSleep features */
+	cap = readl(hpriv->mmio + HOST_CAP);
+	cap2 = readl(hpriv->mmio + HOST_CAP2);
+	if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))
+		return;
+
+	/*
+	 * Tick is generated based on the AXI/AHB application clocks signal
+	 * so we need to be sure in the clock we are going to use.
+	 */
+	aclk = ahci_platform_find_clk(hpriv, "aclk");
+	if (!aclk)
+		return;
+
+	/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */
+	dpriv->timv = readl(hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
+	dpriv->timv = FIELD_GET(DWC_AHCI_HOST_TIMV_MASK, dpriv->timv);
+	rate = clk_get_rate(aclk) / 1000UL;
+	if (rate == dpriv->timv)
+		return;
+
+	dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",
+		 rate / 1000UL);
+	dpriv->timv = FIELD_PREP(DWC_AHCI_HOST_TIMV_MASK, rate);
+	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
+}
+
+static int dwc_ahci_init_dmacr(struct ahci_host_priv *hpriv)
+{
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+	struct device_node *child;
+	void __iomem *port_mmio;
+	u32 port, dmacr, ts;
+
+	/*
+	 * Update the DMA Tx/Rx transaction sizes in accordance with the
+	 * platform setup. Note values exceeding maximal or minimal limits will
+	 * be automatically clamped. Also note the register isn't affected by
+	 * the HBA global reset so we can freely initialize it once until the
+	 * next system reset.
+	 */
+	for_each_child_of_node(dpriv->pdev->dev.of_node, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		if (of_property_read_u32(child, "reg", &port)) {
+			of_node_put(child);
+			return -EINVAL;
+		}
+
+		port_mmio = __ahci_port_base(hpriv, port);
+		dmacr = readl(port_mmio + DWC_AHCI_PORT_DMACR);
+
+		if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
+			ts = ilog2(ts);
+			dmacr &= ~DWC_AHCI_PORT_TXTS_MASK;
+			dmacr |= FIELD_PREP(DWC_AHCI_PORT_TXTS_MASK, ts);
+		}
+
+		if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
+			ts = ilog2(ts);
+			dmacr &= ~DWC_AHCI_PORT_RXTS_MASK;
+			dmacr |= FIELD_PREP(DWC_AHCI_PORT_RXTS_MASK, ts);
+		}
+
+		writel(dmacr, port_mmio + DWC_AHCI_PORT_DMACR);
+		dpriv->dmacr[port] = dmacr;
+	}
+
+	return 0;
+}
+
+static int dwc_ahci_init_host(struct ahci_host_priv *hpriv)
+{
+	int rc;
+
+	rc = ahci_platform_enable_resources(hpriv);
+	if (rc)
+		return rc;
+
+	dwc_ahci_check_cap(hpriv);
+
+	dwc_ahci_init_timer(hpriv);
+
+	rc = dwc_ahci_init_dmacr(hpriv);
+	if (rc)
+		goto err_disable_resources;
+
+	return 0;
+
+err_disable_resources:
+	ahci_platform_disable_resources(hpriv);
+
+	return rc;
+}
+
+static int dwc_ahci_reinit_host(struct ahci_host_priv *hpriv)
+{
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+	unsigned long port_map = hpriv->port_map;
+	void __iomem *port_mmio;
+	int i, rc;
+
+	rc = ahci_platform_enable_resources(hpriv);
+	if (rc)
+		return rc;
+
+	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
+
+	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
+		port_mmio = __ahci_port_base(hpriv, i);
+		writel(dpriv->dmacr[i], port_mmio + DWC_AHCI_PORT_DMACR);
+	}
+
+	return 0;
+}
+
+static void dwc_ahci_clear_host(struct ahci_host_priv *hpriv)
+{
+	ahci_platform_disable_resources(hpriv);
+}
+
+static void dwc_ahci_stop_host(struct ata_host *host)
+{
+	struct ahci_host_priv *hpriv = host->private_data;
+
+	dwc_ahci_clear_host(hpriv);
+}
+
+static struct ata_port_operations dwc_ahci_port_ops = {
+	.inherits	= &ahci_platform_ops,
+	.host_stop	= dwc_ahci_stop_host,
+};
+
+static const struct ata_port_info dwc_ahci_port_info = {
+	.flags		= AHCI_FLAG_COMMON,
+	.pio_mask	= ATA_PIO4,
+	.udma_mask	= ATA_UDMA6,
+	.port_ops	= &dwc_ahci_port_ops,
+};
+
+static struct scsi_host_template dwc_ahci_scsi_info = {
+	AHCI_SHT(DRV_NAME),
+};
+
+static int dwc_ahci_probe(struct platform_device *pdev)
+{
+	struct ahci_host_priv *hpriv;
+	int rc;
+
+	hpriv = dwc_ahci_get_resources(pdev);
+	if (IS_ERR(hpriv))
+		return PTR_ERR(hpriv);
+
+	rc = dwc_ahci_init_host(hpriv);
+	if (rc)
+		return rc;
+
+	rc = ahci_platform_init_host(pdev, hpriv, &dwc_ahci_port_info,
+				     &dwc_ahci_scsi_info);
+	if (rc)
+		goto err_clear_host;
+
+	return 0;
+
+err_clear_host:
+	dwc_ahci_clear_host(hpriv);
+
+	return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc_ahci_suspend(struct device *dev)
+{
+	struct ata_host *host = dev_get_drvdata(dev);
+	struct ahci_host_priv *hpriv = host->private_data;
+	int rc;
+
+	rc = ahci_platform_suspend_host(dev);
+	if (rc)
+		return rc;
+
+	dwc_ahci_clear_host(hpriv);
+
+	return 0;
+}
+
+static int dwc_ahci_resume(struct device *dev)
+{
+	struct ata_host *host = dev_get_drvdata(dev);
+	struct ahci_host_priv *hpriv = host->private_data;
+	int rc;
+
+	rc = dwc_ahci_reinit_host(hpriv);
+	if (rc)
+		return rc;
+
+	return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dwc_ahci_pm_ops, dwc_ahci_suspend, dwc_ahci_resume);
+
+static const struct of_device_id dwc_ahci_of_match[] = {
+	{ .compatible = "snps,dwc-ahci", },
+	{ .compatible = "snps,spear-ahci", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dwc_ahci_of_match);
+
+static struct platform_driver dwc_ahci_driver = {
+	.probe = dwc_ahci_probe,
+	.remove = ata_platform_remove_one,
+	.shutdown = ahci_platform_shutdown,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = dwc_ahci_of_match,
+		.pm = &dwc_ahci_pm_ops,
+	},
+};
+module_platform_driver(dwc_ahci_driver);
+
+MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
+MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 24c25f076f37..052eaa30d262 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -80,9 +80,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
 static const struct of_device_id ahci_of_match[] = {
 	{ .compatible = "generic-ahci", },
 	/* Keep the following compatibles for device tree compatibility */
-	{ .compatible = "snps,spear-ahci", },
 	{ .compatible = "ibm,476gtr-ahci", },
-	{ .compatible = "snps,dwc-ahci", },
 	{ .compatible = "hisilicon,hisi-ahci", },
 	{ .compatible = "cavium,octeon-7130-ahci", },
 	{},
-- 
2.35.1


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

* [PATCH 18/21] dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (16 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 19/21] ata: ahci-dwc: Add platform-specific quirks support Serge Semin
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin, Rob Herring
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, linux-ide,
	linux-kernel, devicetree

Baikal-T1 AHCI controller is based on the DWC AHCI SATA IP-core v4.10a
with the next specific settings: two SATA ports, cascaded CSR access based
on two clock domains (APB and AXI), selectable source of the reference
clock (though stable work is currently available from the external source
only), two reset lanes for the application and SATA ports domains. Other
than that the device is fully compatible with the generic DWC AHCI SATA
bindings.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../bindings/ata/baikal,bt1-ahci.yaml         | 132 ++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml

diff --git a/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml b/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
new file mode 100644
index 000000000000..960d88d97926
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
@@ -0,0 +1,132 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ata/baikal,bt1-ahci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Baikal-T1 SoC AHCI SATA controller
+
+maintainers:
+  - Serge Semin <fancer.lancer@gmail.com>
+
+description: |
+  AHCI SATA controller embedded into the Baikal-T1 SoC is based on the
+  DWC AHCI SATA v4.10a IP-core.
+
+allOf:
+  - $ref: snps,dwc-ahci.yaml#
+
+properties:
+  compatible:
+    contains:
+      const: baikal,bt1-ahci
+
+  clocks:
+    items:
+      - description: Peripheral APB bus clock source
+      - description: Application AXI BIU clock
+      - description: Internal SATA Ports reference clock
+      - description: External SATA Ports reference clock
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: aclk
+      - const: ref_int
+      - const: ref_ext
+
+  resets:
+    items:
+      - description: Application AXI BIU domain reset
+      - description: SATA Ports clock domain reset
+
+  reset-names:
+    items:
+      - const: arst
+      - const: ref
+
+  syscon:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle reference to the CCU system controller. It is required to
+      switch between internal and external SATA reference clock sources.
+
+  ports-implemented:
+    maximum: 0x3
+
+patternProperties:
+  "^sata-port@[0-9a-e]$":
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 1
+
+      snps,tx-ts-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Due to having AXI3 bus interface utilized the maximum Tx DMA
+          transaction size can't exceed 16 beats (AxLEN[3:0]).
+        minimum: 1
+        maximum: 16
+
+      snps,rx-ts-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Due to having AXI3 bus interface utilized the maximum Rx DMA
+          transaction size can't exceed 16 beats (AxLEN[3:0]).
+        minimum: 1
+        maximum: 16
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - syscon
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/mips-gic.h>
+    #include <dt-bindings/clock/bt1-ccu.h>
+    #include <dt-bindings/reset/bt1-ccu.h>
+
+    sata@1f050000 {
+      compatible = "baikal,bt1-ahci", "snps,dwc-ahci";
+      reg = <0x1f050000 0x2000>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      interrupts = <GIC_SHARED 64 IRQ_TYPE_LEVEL_HIGH>;
+
+      clocks = <&ccu_sys CCU_SYS_APB_CLK>, <&ccu_axi CCU_AXI_SATA_CLK>,
+               <&ccu_sys CCU_SYS_SATA_REF_CLK>, <&clk_sata>;
+      clock-names = "pclk", "aclk", "ref_int", "ref_ext";
+
+      resets = <&ccu_axi CCU_AXI_SATA_RST>, <&ccu_sys CCU_SYS_SATA_REF_RST>;
+      reset-names = "arst", "ref";
+
+      syscon = <&syscon>;
+
+      ports-implemented = <0x3>;
+
+      sata-port@0 {
+        reg = <0>;
+
+        snps,tx-ts-max = <4>;
+        snps,rx-ts-max = <4>;
+      };
+
+      sata-port@1 {
+        reg = <1>;
+
+        snps,tx-ts-max = <4>;
+        snps,rx-ts-max = <4>;
+      };
+    };
+...
-- 
2.35.1


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

* [PATCH 19/21] ata: ahci-dwc: Add platform-specific quirks support
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (17 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 18/21] dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support Serge Semin
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

Some DWC AHCI SATA IP-core derivatives require to perform small platform
or IP-core specific setups. They are too small to be placed in a dedicated
driver. It's just much easier to have a set of quirks for them right in
the DWC AHCI driver code. Since we are about to add such platform support,
as a pre-requisite we introduce a platform-data based DWC AHCI quirks API.
The platform data can be used to define the flags passed to the
ahci_platform_get_resources() method, additional AHCI host-flags and a set
of callbacks to initialize, re-initialize and clear the platform settings.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/ahci_dwc.c | 52 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 4 deletions(-)

diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
index c51e2251994e..9e294f994ed3 100644
--- a/drivers/ata/ahci_dwc.c
+++ b/drivers/ata/ahci_dwc.c
@@ -90,7 +90,16 @@
 #define DWC_AHCI_PORT_PHYCR		0x74
 #define DWC_AHCI_PORT_PHYSR		0x78
 
+struct dwc_ahci_plat_data {
+	unsigned int pflags;
+	unsigned int hflags;
+	int (*init)(struct ahci_host_priv *hpriv);
+	int (*reinit)(struct ahci_host_priv *hpriv);
+	void (*clear)(struct ahci_host_priv *hpriv);
+};
+
 struct dwc_ahci_host_priv {
+	const struct dwc_ahci_plat_data *pdata;
 	struct platform_device *pdev;
 
 	u32 timv;
@@ -107,11 +116,15 @@ static struct ahci_host_priv *dwc_ahci_get_resources(struct platform_device *pde
 		return ERR_PTR(-ENOMEM);
 
 	dpriv->pdev = pdev;
+	dpriv->pdata = device_get_match_data(&pdev->dev);
+	if (!dpriv->pdata)
+		return ERR_PTR(-EINVAL);
 
-	hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
+	hpriv = ahci_platform_get_resources(pdev, dpriv->pdata->pflags);
 	if (IS_ERR(hpriv))
 		return hpriv;
 
+	hpriv->flags |= dpriv->pdata->hflags;
 	hpriv->plat_data = (void *)dpriv;
 
 	return hpriv;
@@ -242,22 +255,33 @@ static int dwc_ahci_init_dmacr(struct ahci_host_priv *hpriv)
 
 static int dwc_ahci_init_host(struct ahci_host_priv *hpriv)
 {
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
 	int rc;
 
 	rc = ahci_platform_enable_resources(hpriv);
 	if (rc)
 		return rc;
 
+	if (dpriv->pdata->init) {
+		rc = dpriv->pdata->init(hpriv);
+		if (rc)
+			goto err_disable_resources;
+	}
+
 	dwc_ahci_check_cap(hpriv);
 
 	dwc_ahci_init_timer(hpriv);
 
 	rc = dwc_ahci_init_dmacr(hpriv);
 	if (rc)
-		goto err_disable_resources;
+		goto err_clear_platform;
 
 	return 0;
 
+err_clear_platform:
+	if (dpriv->pdata->clear)
+		dpriv->pdata->clear(hpriv);
+
 err_disable_resources:
 	ahci_platform_disable_resources(hpriv);
 
@@ -275,6 +299,12 @@ static int dwc_ahci_reinit_host(struct ahci_host_priv *hpriv)
 	if (rc)
 		return rc;
 
+	if (dpriv->pdata->reinit) {
+		rc = dpriv->pdata->reinit(hpriv);
+		if (rc)
+			goto err_disable_resources;
+	}
+
 	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
 
 	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
@@ -283,10 +313,20 @@ static int dwc_ahci_reinit_host(struct ahci_host_priv *hpriv)
 	}
 
 	return 0;
+
+err_disable_resources:
+	ahci_platform_disable_resources(hpriv);
+
+	return rc;
 }
 
 static void dwc_ahci_clear_host(struct ahci_host_priv *hpriv)
 {
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+
+	if (dpriv->pdata->clear)
+		dpriv->pdata->clear(hpriv);
+
 	ahci_platform_disable_resources(hpriv);
 }
 
@@ -371,9 +411,13 @@ static int dwc_ahci_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(dwc_ahci_pm_ops, dwc_ahci_suspend, dwc_ahci_resume);
 
+struct dwc_ahci_plat_data dwc_ahci_plat = {
+	.pflags = AHCI_PLATFORM_GET_RESETS,
+};
+
 static const struct of_device_id dwc_ahci_of_match[] = {
-	{ .compatible = "snps,dwc-ahci", },
-	{ .compatible = "snps,spear-ahci", },
+	{ .compatible = "snps,dwc-ahci", &dwc_ahci_plat },
+	{ .compatible = "snps,spear-ahci", &dwc_ahci_plat },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dwc_ahci_of_match);
-- 
2.35.1


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

* [PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (18 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 19/21] ata: ahci-dwc: Add platform-specific quirks support Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  0:16 ` [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver Serge Semin
  2022-03-28 20:06 ` [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Damien Le Moal
  21 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

It's almost fully compatible DWC AHCI SATA IP-core derivative except the
reference clocks source, which need to be very carefully selected. In
particular the DWC AHCI SATA PHY can be clocked either from the pads
ref_pad_clk_{m,p} or from the internal wires ref_alt_clk_{m,n}. In the
later case the clock signal is generated from the Baikal-T1 CCU SATA PLL.
The clocks source is selected by means of the ref_use_pad wire connected
to the CCU SATA reference clock CSR.

In normal situation it would be much more handy to use the internal
reference clock source, but alas we haven't managed to make the AHCI
controller working well with it so far. So it's preferable to have the
controller clocked from the external clock generator and fallback to the
internal clock source only as a last resort. Other than that the
controller is full compatible with the DWC AHCI SATA IP-core.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/ata/Kconfig    |  1 +
 drivers/ata/ahci_dwc.c | 86 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ab11bcf8510c..003f000a69a7 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -178,6 +178,7 @@ config AHCI_DWC
 	tristate "Synopsys DWC AHCI SATA support"
 	select SATA_HOST
 	default SATA_AHCI_PLATFORM
+	select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
 	help
 	  This option enables support for the Synopsys DWC AHCI SATA
 	  controller implementation.
diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
index 9e294f994ed3..efcd5f74c2d4 100644
--- a/drivers/ata/ahci_dwc.c
+++ b/drivers/ata/ahci_dwc.c
@@ -13,10 +13,12 @@
 #include <linux/kernel.h>
 #include <linux/libata.h>
 #include <linux/log2.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/regmap.h>
 
 #include "ahci.h"
 
@@ -90,6 +92,26 @@
 #define DWC_AHCI_PORT_PHYCR		0x74
 #define DWC_AHCI_PORT_PHYSR		0x78
 
+/* Baikal-T1 AHCI SATA specific registers */
+#define BT1_AHCI_HOST_PHYCR		DWC_AHCI_HOST_GPCR
+#define BT1_AHCI_HOST_MPLM_MASK		GENMASK(29, 23)
+#define BT1_AHCI_HOST_LOSDT_MASK	GENMASK(22, 20)
+#define BT1_AHCI_HOST_CRR		BIT(19)
+#define BT1_AHCI_HOST_CRW		BIT(18)
+#define BT1_AHCI_HOST_CRCD		BIT(17)
+#define BT1_AHCI_HOST_CRCA		BIT(16)
+#define BT1_AHCI_HOST_CRDI_MASK		GENMASK(15, 0)
+
+#define BT1_AHCI_HOST_PHYSR		DWC_AHCI_HOST_GPSR
+#define BT1_AHCI_HOST_CRA		BIT(16)
+#define BT1_AHCI_HOST_CRDO_MASK		GENMASK(15, 0)
+
+/* Baikal-T1 CCU registers concerning the AHCI SATA module */
+#define BT1_CCU_SYS_SATA_REF		0x60
+#define BT1_CCU_SYS_SATA_REF_EXT	BIT(28)
+#define BT1_CCU_SYS_SATA_REF_INV	BIT(29)
+#define BT1_CCU_SYS_SATA_REF_BUF	BIT(30)
+
 struct dwc_ahci_plat_data {
 	unsigned int pflags;
 	unsigned int hflags;
@@ -106,6 +128,64 @@ struct dwc_ahci_host_priv {
 	u32 dmacr[AHCI_MAX_PORTS];
 };
 
+static int bt1_ahci_init(struct ahci_host_priv *hpriv)
+{
+	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
+	struct regmap *sys_regs;
+	u32 ref_ctl, mask;
+
+	/* APB and application clocks are required */
+	if (!ahci_platform_find_clk(hpriv, "pclk") ||
+	    !ahci_platform_find_clk(hpriv, "aclk")) {
+		dev_err(&dpriv->pdev->dev, "No system clocks specified\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * We need to select the PHY reference clock source. The signal
+	 * can be delivered either from the chip pads or from the internal
+	 * PLL. The source is selected by the PHY's ref_use_pad signal
+	 * tied up into one of the CCU SATA ref-ctl register field.
+	 */
+	sys_regs = syscon_regmap_lookup_by_phandle(dpriv->pdev->dev.of_node, "syscon");
+	if (IS_ERR(sys_regs)) {
+		dev_err(&dpriv->pdev->dev, "CCU syscon couldn't be found\n");
+		return PTR_ERR(sys_regs);
+	}
+
+	(void)regmap_read(sys_regs, BT1_CCU_SYS_SATA_REF, &ref_ctl);
+
+	/*
+	 * Prefer activating external reference clock if one is supplied.
+	 * If there is no external ref clock, then we have no choice but
+	 * to fall back to the internal signal coming from PLL. Alas
+	 * we haven't managed to make the interface working well when it's
+	 * used so far, but in no alternative let's at least try...
+	 */
+	if (ahci_platform_find_clk(hpriv, "ref_ext")) {
+		ref_ctl |= BT1_CCU_SYS_SATA_REF_EXT;
+		mask = BT1_CCU_SYS_SATA_REF_EXT;
+	} else if (ahci_platform_find_clk(hpriv, "ref_int")) {
+		ref_ctl &= ~BT1_CCU_SYS_SATA_REF_EXT;
+		ref_ctl |= BT1_CCU_SYS_SATA_REF_INV | BT1_CCU_SYS_SATA_REF_BUF;
+		mask = BT1_CCU_SYS_SATA_REF_EXT |
+		       BT1_CCU_SYS_SATA_REF_INV | BT1_CCU_SYS_SATA_REF_BUF;
+		dev_warn(&dpriv->pdev->dev, "Fallback to PLL-based ref clock!\n");
+	} else {
+		dev_err(&dpriv->pdev->dev, "No ref clock specified\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(sys_regs, BT1_CCU_SYS_SATA_REF, mask, ref_ctl);
+
+	/*
+	 * Fully reset the SATA AXI and ref clocks domain so to ensure the
+	 * state machine is working from scratch.
+	 */
+	ahci_platform_assert_rsts(hpriv);
+	return ahci_platform_deassert_rsts(hpriv);
+}
+
 static struct ahci_host_priv *dwc_ahci_get_resources(struct platform_device *pdev)
 {
 	struct dwc_ahci_host_priv *dpriv;
@@ -415,9 +495,15 @@ struct dwc_ahci_plat_data dwc_ahci_plat = {
 	.pflags = AHCI_PLATFORM_GET_RESETS,
 };
 
+struct dwc_ahci_plat_data bt1_ahci_plat = {
+	.pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER,
+	.init = bt1_ahci_init,
+};
+
 static const struct of_device_id dwc_ahci_of_match[] = {
 	{ .compatible = "snps,dwc-ahci", &dwc_ahci_plat },
 	{ .compatible = "snps,spear-ahci", &dwc_ahci_plat },
+	{ .compatible = "baikal,bt1-ahci", &bt1_ahci_plat },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dwc_ahci_of_match);
-- 
2.35.1


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

* [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (19 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support Serge Semin
@ 2022-03-24  0:16 ` Serge Semin
  2022-03-24  2:17   ` Damien Le Moal
  2022-03-28 20:06 ` [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Damien Le Moal
  21 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24  0:16 UTC (permalink / raw)
  To: Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Add myself as a maintainer of the new DWC AHCI SATA driver and
its DT-bindings schema.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index cd0f68d4a34a..19c9ea0758cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10919,6 +10919,15 @@ F:	drivers/ata/ahci_platform.c
 F:	drivers/ata/libahci_platform.c
 F:	include/linux/ahci_platform.h
 
+LIBATA SATA AHCI SYNOPSYS DWC CONTROLLER DRIVER
+M:	Serge Semin <fancer.lancer@gmail.com>
+L:	linux-ide@vger.kernel.org
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
+F:	Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
+F:	Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
+F:	drivers/ata/ahci_dwc.c
+
 LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
 M:	Mikael Pettersson <mikpelinux@gmail.com>
 L:	linux-ide@vger.kernel.org
-- 
2.35.1


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

* Re: [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
@ 2022-03-24  0:58   ` Damien Le Moal
  2022-03-24 21:37     ` Serge Semin
  2022-03-29  8:20   ` Damien Le Moal
  1 sibling, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  0:58 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> It's better for readability and maintainability to explicitly assign an
> error number to the variable used then as a return value from the method
> on the cleanup-on-error path. So adding new code in the method we won't

No it is not. On-stack variable initialization is not free. So if
initializing the variable is not needed, do not do it.

> have to think whether the overridden rc-variable is set afterward in case
> of an error. Saving one line of code doesn't worth it especially seeing
> the rest of the ahci_platform_get_resources() function errors handling
> blocks do explicitly write errno to rc.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/libahci_platform.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 18296443ccba..1bd2f1686239 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  	struct ahci_host_priv *hpriv;
>  	struct clk *clk;
>  	struct device_node *child;
> -	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
> +	int i, enabled_ports = 0, rc = 0, child_nodes;
>  	u32 mask_port_map = 0;
>  
>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> @@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  
>  	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
>  			     GFP_KERNEL);
> -	if (!hpriv)
> +	if (!hpriv) {
> +		rc = -ENOMEM;
>  		goto err_out;
> +	}

If you set rc to -ENOMEM here, then the 0 initialization of rc is not needed.

>  
>  	devres_add(dev, hpriv);
>  


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods
  2022-03-24  0:16 ` [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods Serge Semin
@ 2022-03-24  1:11   ` Damien Le Moal
  2022-04-06 20:42     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  1:11 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Currently the IOMEM AHCI registers space is mapped by means of the
> two functions invocation: platform_get_resource() is used to get the very
> first memory resource and devm_ioremap_resource() is called to remap that
> resource. Device-managed kernel API provides a handy wrapper to perform
> the same in single function call: devm_platform_ioremap_resource().

> 
> While at it seeing many AHCI platform drivers rely on having the AHCI CSR
> space marked with "ahci" name let's first try to find and remap the CSR
> IO-mem with that name and only if it fails fallback to getting the very
> first registers space platform resource.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/libahci_platform.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 1bd2f1686239..8eabbb5f208c 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -404,11 +404,13 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  
>  	devres_add(dev, hpriv);
>  
> -	hpriv->mmio = devm_ioremap_resource(dev,
> -			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
> +	hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");

See __devm_ioremap_resource(): if there is no resource named "ahci" found,
then this will print an error message ("invalid resource\n"). That may
confuse users as this error message was not present before. So you may
want to change this code to something like this:

/*
 * If the DT provided an "ahci" named resource, use it. Otherwise,
 * fallback to using the default first resource for the device node.
 */
if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"))
	hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");
else
	hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hpriv->mmio)) {
	rc = PTR_ERR(hpriv->mmio);
	goto err_out;
}

>  	if (IS_ERR(hpriv->mmio)) {
> -		rc = PTR_ERR(hpriv->mmio);
> -		goto err_out;
> +		hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
> +		if (IS_ERR(hpriv->mmio)) {
> +			rc = PTR_ERR(hpriv->mmio);
> +			goto err_out;
> +		}
>  	}
>  
>  	for (i = 0; i < AHCI_MAX_CLKS; i++) {


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
@ 2022-03-24  1:29   ` Damien Le Moal
  2022-04-09  4:59     ` Serge Semin
  2022-03-28 22:36   ` kernel test robot
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  1:29 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> In order to simplify the clock-related code there is a way to convert the
> current fixed clocks array into using the common bulk clocks kernel API
> with dynamic set of the clock handlers and device-managed clock-resource
> tracking. It's a bit tricky due to the complication coming from the
> requirement to support the platforms (da850, spear13xx) with the
> non-OF-based clock source, but still doable.
> 
> Before this modification there are two methods have been used to get the
> clocks connected to an AHCI device: clk_get() - to get the very first
> clock in the list and of_clk_get() - to get the rest of them. Basically
> the platforms with non-OF-based clocks definition could specify only a
> single reference clock source. The platforms with OF-hw clocks have been
> luckier and could setup up to AHCI_MAX_CLKS clocks. Such semantic can be
> retained with using devm_clk_bulk_get_all() to retrieve the clocks defined
> via the DT firmware and devm_clk_get_optional() otherwise. In both cases
> using the device-managed version of the methods will cause the automatic
> resources deallocation on the AHCI device removal event. The only
> complicated part in the suggested approach is the explicit allocation and
> initialization of the clk_bulk_data structure instance for the non-OF
> reference clocks. It's required in order to use the Bulk Clocks API for
> the both denoted cases of the clocks definition.
> 
> Note aside with the clock-related code reduction and natural
> simplification, there are several bonuses the suggested modification
> provides. First of all the limitation of having no greater than
> AHCI_MAX_CLKS clocks is now removed, since the devm_clk_bulk_get_all()
> method will allocate as many reference clocks data descriptors as there
> are clocks specified for the device. Secondly the clock names are
> auto-detected. So the glue drivers can make sure that the required clocks
> are specified just by checking the clock IDs in the clk_bulk_data array.
> Thirdly using the handy Bulk Clocks kernel API improves the
> clocks-handling code readability. And the last but not least this
> modification implements a true optional clocks support to the
> ahci_platform_get_resources() method. Indeed the previous clocks getting
> procedure just stopped getting the clocks on any errors (aside from
> non-critical -EPROBE_DEFER) in a way so the callee wasn't even informed
> about abnormal loop termination. The new implementation lacks of such
> problem. The ahci_platform_get_resources() will return an error code if
> the corresponding clocks getting method ends execution abnormally.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/ahci.h             |  4 +-
>  drivers/ata/libahci_platform.c | 82 +++++++++++++++-------------------
>  2 files changed, 37 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> index eeac5482f1d1..1564c691094a 100644
> --- a/drivers/ata/ahci.h
> +++ b/drivers/ata/ahci.h
> @@ -38,7 +38,6 @@
>  
>  enum {
>  	AHCI_MAX_PORTS		= 32,
> -	AHCI_MAX_CLKS		= 5,
>  	AHCI_MAX_SG		= 168, /* hardware max is 64K */
>  	AHCI_DMA_BOUNDARY	= 0xffffffff,
>  	AHCI_MAX_CMDS		= 32,
> @@ -341,7 +340,8 @@ struct ahci_host_priv {
>  	u32			em_msg_type;	/* EM message type */
>  	u32			remapped_nvme;	/* NVMe remapped device count */
>  	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
> -	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
> +	unsigned int		n_clks;
> +	struct clk_bulk_data	*clks;		/* Optional */
>  	struct reset_control	*rsts;		/* Optional */
>  	struct regulator	**target_pwrs;	/* Optional */
>  	struct regulator	*ahci_regulator;/* Optional */
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 8eabbb5f208c..d805ddc3a024 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -8,6 +8,7 @@
>   *   Anton Vorontsov <avorontsov@ru.mvista.com>
>   */
>  
> +#include <linux/clk-provider.h>
>  #include <linux/clk.h>
>  #include <linux/kernel.h>
>  #include <linux/gfp.h>
> @@ -97,28 +98,14 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
>   * ahci_platform_enable_clks - Enable platform clocks
>   * @hpriv: host private area to store config values
>   *
> - * This function enables all the clks found in hpriv->clks, starting at
> - * index 0. If any clk fails to enable it disables all the clks already
> - * enabled in reverse order, and then returns an error.
> + * This function enables all the clks found for the AHCI device.
>   *
>   * RETURNS:
>   * 0 on success otherwise a negative error code
>   */
>  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
>  {
> -	int c, rc;
> -
> -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
> -		rc = clk_prepare_enable(hpriv->clks[c]);
> -		if (rc)
> -			goto disable_unprepare_clk;
> -	}
> -	return 0;
> -
> -disable_unprepare_clk:
> -	while (--c >= 0)
> -		clk_disable_unprepare(hpriv->clks[c]);
> -	return rc;
> +	return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
>  
> @@ -126,16 +113,13 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
>   * ahci_platform_disable_clks - Disable platform clocks
>   * @hpriv: host private area to store config values
>   *
> - * This function disables all the clks found in hpriv->clks, in reverse
> - * order of ahci_platform_enable_clks (starting at the end of the array).
> + * This function disables all the clocks enabled before
> + * (bulk-clocks-disable function is supposed to do that in reverse
> + * from the enabling procedure order).
>   */
>  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
>  {
> -	int c;
> -
> -	for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
> -		if (hpriv->clks[c])
> -			clk_disable_unprepare(hpriv->clks[c]);
> +	clk_bulk_disable_unprepare(hpriv->n_clks, hpriv->clks);
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
>  
> @@ -292,8 +276,6 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
>  		pm_runtime_disable(dev);
>  	}
>  
> -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
> -		clk_put(hpriv->clks[c]);
>  	/*
>  	 * The regulators are tied to child node device and not to the
>  	 * SATA device itself. So we can't use devm for automatically
> @@ -374,8 +356,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
>   * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
>   * 2) regulator for controlling the targets power (optional)
>   *    regulator for controlling the AHCI controller (optional)
> - * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
> - *    or for non devicetree enabled platforms a single clock
> + * 3) all clocks specified in the devicetree node, or a single
> + *    clock for non-OF platforms (optional)
>   * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
>   * 5) phys (optional)
>   *
> @@ -385,11 +367,10 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
>  struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  						   unsigned int flags)
>  {
> +	int enabled_ports = 0, rc = 0, child_nodes;
>  	struct device *dev = &pdev->dev;
>  	struct ahci_host_priv *hpriv;
> -	struct clk *clk;
>  	struct device_node *child;
> -	int i, enabled_ports = 0, rc = 0, child_nodes;
>  	u32 mask_port_map = 0;
>  
>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> @@ -413,25 +394,32 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  		}
>  	}
>  
> -	for (i = 0; i < AHCI_MAX_CLKS; i++) {
> -		/*
> -		 * For now we must use clk_get(dev, NULL) for the first clock,
> -		 * because some platforms (da850, spear13xx) are not yet
> -		 * converted to use devicetree for clocks.  For new platforms
> -		 * this is equivalent to of_clk_get(dev->of_node, 0).
> -		 */
> -		if (i == 0)
> -			clk = clk_get(dev, NULL);
> -		else
> -			clk = of_clk_get(dev->of_node, i);
> -
> -		if (IS_ERR(clk)) {
> -			rc = PTR_ERR(clk);
> -			if (rc == -EPROBE_DEFER)
> -				goto err_out;
> -			break;
> +	/*
> +	 * Bulk clock get procedure can fail to find any clock due to running
> +	 * an a non-OF platform or due to the clocks being defined in bypass
> +	 * from the DT firmware (like da850, spear13xx). In that case we
> +	 * fallback to getting a single clock source right from the dev clocks
> +	 * list.
> +	 */
> +	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);

I would move the error check first here to make things more readable:

	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
	if (rc < 0)
		goto err_out;

	if (rc) {
		/* Got clocks in bulk */
		hpriv->n_clks = rc;
	} else {
		/*
		 * No clock bulk found: fallback to manually getting
		 * the optional clock.
		 */
		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks),
					   GFP_KERNEL);
		...
	}

And it may be cleaner to move this entire code hunk into a helper,
something like ahci_platform_get_clks() ?

> +	if (rc > 0) {
> +		hpriv->n_clks = rc;
> +	} else if (!rc) {
> +		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks), GFP_KERNEL);
> +		if (!hpriv->clks) {
> +			rc = -ENOMEM;
> +			goto err_out;
>  		}
> -		hpriv->clks[i] = clk;
> +		hpriv->clks->clk = devm_clk_get_optional(dev, NULL);
> +		if (IS_ERR(hpriv->clks->clk)) {
> +			rc = PTR_ERR(hpriv->clks->clk);
> +			goto err_out;
> +		} else if (hpriv->clks->clk) {
> +			hpriv->clks->id = __clk_get_name(hpriv->clks->clk);
> +			hpriv->n_clks = 1;
> +		}
> +	} else {
> +		goto err_out;
>  	}
>  
>  	hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id
  2022-03-24  0:16 ` [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id Serge Semin
@ 2022-03-24  1:36   ` Damien Le Moal
  2022-04-11  6:02     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  1:36 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Since all the clocks are retrieved by the method
> ahci_platform_get_resources() there is no need for the glue-drivers to be
> looking for some particular of them in the kernel clocks table again.
> Instead we suggest to add a simple method returning a device-specific
> clock with passed connection ID if it is managed to be found. Otherwise
> the function will return NULL. Thus the glue-drivers won't need to either

"glue-drivers" is really unclear. What do you mean ?

> manually touching the hpriv->clks array or calling clk_get()-friends. The
> AHCI platform drivers will be able to use the new function right after the
> ahci_platform_get_resources() method invocation and up to the device
> removal.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/libahci_platform.c | 27 +++++++++++++++++++++++++++
>  include/linux/ahci_platform.h  |  3 +++
>  2 files changed, 30 insertions(+)
> 
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index d805ddc3a024..4fb9629c03ab 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -94,6 +94,33 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
>  
> +/**
> + * ahci_platform_find_clk - Find platform clock
> + * @hpriv: host private area to store config values
> + * @con_id: clock connection ID
> + *
> + * This function returns point to the clock descriptor of the clock with
> + * passed ID.
> + *
> + * RETURNS:
> + * Pointer to the clock descriptor on success otherwise NULL
> + */
> +struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id)
> +{
> +	struct clk *clk = NULL;
> +	int i;
> +
> +	for (i = 0; i < hpriv->n_clks; i++) {
> +		if (!strcmp(hpriv->clks[i].id, con_id)) {
> +			clk = hpriv->clks[i].clk;
> +			break;
> +		}
> +	}
> +
> +	return clk;
> +}
> +EXPORT_SYMBOL_GPL(ahci_platform_find_clk);
> +
>  /**
>   * ahci_platform_enable_clks - Enable platform clocks
>   * @hpriv: host private area to store config values
> diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
> index 49e5383d4222..fd964e6a68d6 100644
> --- a/include/linux/ahci_platform.h
> +++ b/include/linux/ahci_platform.h
> @@ -13,6 +13,7 @@
>  
>  #include <linux/compiler.h>
>  
> +struct clk;
>  struct device;
>  struct ata_port_info;
>  struct ahci_host_priv;
> @@ -21,6 +22,8 @@ struct scsi_host_template;
>  
>  int ahci_platform_enable_phys(struct ahci_host_priv *hpriv);
>  void ahci_platform_disable_phys(struct ahci_host_priv *hpriv);
> +struct clk *
> +ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);

No users for this function ?

>  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
>  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
>  int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number
  2022-03-24  0:16 ` [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number Serge Semin
@ 2022-03-24  1:40   ` Damien Le Moal
  2022-03-24  8:12     ` Sergey Shtylyov
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  1:40 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Having greater than (AHCI_MAX_PORTS = 32) ports detected isn't that
> critical from the further AHCI-platform initialization point of view since
> exceeding the ports upper limit will cause allocating more resources than
> will be used afterwards. But detecting too many child DT-nodes doesn't
> seem right since it's very unlikely to have it on an ordinary platform. In
> accordance with the AHCI specification there can't be more than 32 ports
> implemented at least due to having the CAP.NP field of 4 bits wide and the
> PI register of dword size. Thus if such situation is found the DTB must
> have been corrupted and the data read from it shouldn't be reliable. Let's
> consider that as an erroneous situation and halt further resources
> allocation.
> 
> Note it's logically more correct to have the nports set only after the
> initialization value is checked for being sane. So while at it let's make
> sure nports is assigned with a correct value.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/libahci_platform.c | 16 +++++++++++-----
>  1 file changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 4fb9629c03ab..845042295b97 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -470,15 +470,21 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  		}
>  	}
>  
> -	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
> -
>  	/*
> -	 * If no sub-node was found, we still need to set nports to
> -	 * one in order to be able to use the
> +	 * Too many sub-nodes most likely means having something wrong with
> +	 * firmware. If no sub-node was found, we still need to set nports
> +	 * to one in order to be able to use the
>  	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
>  	 */
> -	if (!child_nodes)
> +	child_nodes = of_get_child_count(dev->of_node);
> +	if (child_nodes > AHCI_MAX_PORTS) {
> +		rc = -EINVAL;
> +		goto err_out;
> +	} else if (!child_nodes) {

No need for "else" after a return.

>  		hpriv->nports = 1;
> +	} else {
> +		hpriv->nports = child_nodes;
> +	}
>  
>  	hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
>  	if (!hpriv->phys) {


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods
  2022-03-24  0:16 ` [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods Serge Semin
@ 2022-03-24  1:52   ` Damien Le Moal
  2022-04-11 10:57     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  1:52 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Currently the ACHI-platform library supports only the assert and deassert
> reset signals and ignores the platforms with self-deasserting reset lines.
> That prone to having the platforms with self-deasserting reset method
> misbehaviour when it comes to resuming from sleep state after the clocks
> have been fully disabled. For such cases the controller needs to be fully
> reset all over after the reference clocks are enabled and stable,
> otherwise the controller state machine might be in an undetermined state.
> 
> The best solution would be to auto-detect which reset method is supported
> by the particular platform and use it implicitly in the framework of the
> ahci_platform_enable_resources()/ahci_platform_disable_resources()
> methods. Alas it can't be implemented due to the AHCI-platform library
> already supporting the shared reset control lines. As [1] says in such
> case we have to use only one of the next methods:
> + reset_control_assert()/reset_control_deassert();
> + reset_control_reset()/reset_control_rearm().
> If the driver had an exclusive control over the reset lines we could have
> been able to manipulate the lines with no much limitation and just used
> the combination of the methods above to cover all the possible
> reset-control cases. Since the shared reset control has already been
> advertised and couldn't be changed with no risk to breaking the platforms
> relying on it, we have no choice but to make the platform drivers to
> determine which reset methods the platform reset system supports.
> 
> In order to implement both types of reset control support we suggest to
> introduce the new AHCI-platform flag: AHCI_PLATFORM_RST_TRIGGER, which
> when passed to the ahci_platform_get_resources() method together with the
> AHCI_PLATFORM_GET_RESETS flag will indicate that the reset lines are
> self-deasserting thus the reset_control_reset()/reset_control_rearm() will
> be used to control the reset state. Otherwise the
> reset_control_deassert()/reset_control_assert() methods will be utilized.
> 
> [1] Documentation/driver-api/reset.rst
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/ahci.h             |  1 +
>  drivers/ata/libahci_platform.c | 47 ++++++++++++++++++++++++++++++----
>  include/linux/ahci_platform.h  |  5 +++-
>  3 files changed, 47 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> index 1564c691094a..0b1d5c24cb8c 100644
> --- a/drivers/ata/ahci.h
> +++ b/drivers/ata/ahci.h
> @@ -342,6 +342,7 @@ struct ahci_host_priv {
>  	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
>  	unsigned int		n_clks;
>  	struct clk_bulk_data	*clks;		/* Optional */
> +	unsigned int		f_rsts;

Why ? using flags directly is not OK ?

>  	struct reset_control	*rsts;		/* Optional */
>  	struct regulator	**target_pwrs;	/* Optional */
>  	struct regulator	*ahci_regulator;/* Optional */
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 5998e735a813..febad33aa43c 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -150,6 +150,41 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
>  
> +/**
> + * ahci_platform_deassert_rsts - Deassert/trigger platform resets
> + * @hpriv: host private area to store config values
> + *
> + * This function desserts or triggers all the reset lanes found for the AHCI

s/desserts/deasserts ?
s/lanes/lines ?

> + * device.
> + *
> + * RETURNS:
> + * 0 on success otherwise a negative error code
> + */
> +int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv)
> +{
> +	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
> +		return reset_control_reset(hpriv->rsts);
> +
> +	return reset_control_deassert(hpriv->rsts);
> +}
> +EXPORT_SYMBOL_GPL(ahci_platform_deassert_rsts);
> +
> +/**
> + * ahci_platform_assert_rsts - Assert/rearm platform resets
> + * @hpriv: host private area to store config values
> + *
> + * This function asserts or rearms (for self-deasserting resets) all the reset
> + * controls found for the AHCI device.
> + */
> +void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv)
> +{
> +	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
> +		return (void)reset_control_rearm(hpriv->rsts);

return void in a void function ? How does this even compile ?
And what if reset_control_rearm() fails ? What happens ?

> +
> +	reset_control_assert(hpriv->rsts);
> +}
> +EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts);
> +
>  /**
>   * ahci_platform_enable_regulators - Enable regulators
>   * @hpriv: host private area to store config values
> @@ -247,18 +282,18 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
>  	if (rc)
>  		goto disable_regulator;
>  
> -	rc = reset_control_deassert(hpriv->rsts);
> +	rc = ahci_platform_deassert_rsts(hpriv);
>  	if (rc)
>  		goto disable_clks;
>  
>  	rc = ahci_platform_enable_phys(hpriv);
>  	if (rc)
> -		goto disable_resets;
> +		goto disable_rsts;
>  
>  	return 0;
>  
> -disable_resets:
> -	reset_control_assert(hpriv->rsts);
> +disable_rsts:
> +	ahci_platform_assert_rsts(hpriv);
>  
>  disable_clks:
>  	ahci_platform_disable_clks(hpriv);
> @@ -285,7 +320,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
>  {
>  	ahci_platform_disable_phys(hpriv);
>  
> -	reset_control_assert(hpriv->rsts);
> +	ahci_platform_assert_rsts(hpriv);
>  
>  	ahci_platform_disable_clks(hpriv);
>  
> @@ -468,6 +503,8 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  			rc = PTR_ERR(hpriv->rsts);
>  			goto err_out;
>  		}
> +
> +		hpriv->f_rsts = flags & AHCI_PLATFORM_RST_TRIGGER;

Why not use hpriv->flags ?

>  	}
>  
>  	/*
> diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
> index fd964e6a68d6..57d25d30a9fa 100644
> --- a/include/linux/ahci_platform.h
> +++ b/include/linux/ahci_platform.h
> @@ -26,6 +26,8 @@ struct clk *
>  ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);
>  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
>  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
> +int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv);
> +void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv);
>  int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
>  void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
>  int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
> @@ -44,6 +46,7 @@ int ahci_platform_resume_host(struct device *dev);
>  int ahci_platform_suspend(struct device *dev);
>  int ahci_platform_resume(struct device *dev);
>  
> -#define AHCI_PLATFORM_GET_RESETS	0x01
> +#define AHCI_PLATFORM_GET_RESETS	BIT(0)
> +#define AHCI_PLATFORM_RST_TRIGGER	BIT(1)
>  
>  #endif /* _AHCI_PLATFORM_H */


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-03-24  0:16 ` [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter Serge Semin
@ 2022-03-24  2:05   ` Damien Le Moal
  2022-04-11 12:11     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  2:05 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Currently there are four port-map-related fields declared in the
> ahci_host_priv structure and used to setup the HBA ports mapping. First
> the ports-mapping is read from the PI register and immediately stored in
> the saved_port_map field. If forced_port_map is initialized with non-zero
> value then its value will have greater priority over the value read from
> PI, thus it will override the saved_port_map field. That value will be then
> masked by a non-zero mask_port_map field and after some sanity checks it
> will be stored in the ahci_host_priv.port_map field as a final port
> mapping.
> 
> As you can see the logic is a bit too complicated for such a simple task.
> We can freely get rid from at least one of the fields with no change to
> the implemented semantic. The force_port_map field can be replaced with
> taking non-zero saved_port_map value into account. So if saved_port_map is
> pre-initialized by the glue-driver/platform-specific code then it will

glue-driver == LLDD (low level device driver), for the entire series please.

> have greater priority over the value read from PI register and will be
> used as actual HBA ports mapping later on. Thus the ports map forcing task
> will be just transferred from the force_port_map to saved_port_map field.
> 
> This modification will perfectly fit into the feature of having OF-based
> initialization of the HW-init HBA CSR fields we are about to introduce in
> the next commit.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/ahci.c             |  2 +-
>  drivers/ata/ahci.h             |  1 -
>  drivers/ata/libahci.c          | 10 ++++++----
>  drivers/ata/libahci_platform.c |  2 +-
>  4 files changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
> index ab5811ef5a53..8ce0d166cc8d 100644
> --- a/drivers/ata/ahci.c
> +++ b/drivers/ata/ahci.c
> @@ -654,7 +654,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
>  {
>  	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
>  		dev_info(&pdev->dev, "JMB361 has only one port\n");
> -		hpriv->force_port_map = 1;
> +		hpriv->saved_port_map = 1;
>  	}
>  
>  	/*
> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> index 04690b4168a3..519d148ecaea 100644
> --- a/drivers/ata/ahci.h
> +++ b/drivers/ata/ahci.h
> @@ -329,7 +329,6 @@ struct ahci_port_priv {
>  struct ahci_host_priv {
>  	/* Input fields */
>  	unsigned int		flags;		/* AHCI_HFLAG_* */
> -	u32			force_port_map;	/* force port map */
>  	u32			mask_port_map;	/* mask out particular bits */
>  
>  	void __iomem *		mmio;		/* bus-independent mem map */
> diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
> index 0ed484e04fd6..011175e82174 100644
> --- a/drivers/ata/libahci.c
> +++ b/drivers/ata/libahci.c
> @@ -453,7 +453,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
>  	 * reset.  Values without are used for driver operation.
>  	 */
>  	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
> -	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
>  
>  	/* CAP2 register is only defined for AHCI 1.2 and later */
>  	vers = readl(mmio + HOST_VERSION);
> @@ -517,10 +516,13 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
>  		cap &= ~HOST_CAP_SXS;
>  	}
>  
> -	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
> +	/* Override the HBA ports mapping if the platform needs it */
> +	port_map = readl(mmio + HOST_PORTS_IMPL);
> +	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
>  		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
> -			 port_map, hpriv->force_port_map);
> -		port_map = hpriv->force_port_map;
> +			 port_map, hpriv->saved_port_map);
> +		port_map = hpriv->saved_port_map;
> +	} else {
>  		hpriv->saved_port_map = port_map;
>  	}
>  
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index febad33aa43c..5cbc2c42164d 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -539,7 +539,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  	}
>  
>  	of_property_read_u32(dev->of_node,
> -			     "ports-implemented", &hpriv->force_port_map);
> +			     "ports-implemented", &hpriv->saved_port_map);
>  
>  	if (child_nodes) {
>  		for_each_child_of_node(dev->of_node, child) {


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver
  2022-03-24  0:16 ` [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver Serge Semin
@ 2022-03-24  2:17   ` Damien Le Moal
  2022-04-11 12:16     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  2:17 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Add myself as a maintainer of the new DWC AHCI SATA driver and
> its DT-bindings schema.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  MAINTAINERS | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index cd0f68d4a34a..19c9ea0758cc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10919,6 +10919,15 @@ F:	drivers/ata/ahci_platform.c
>  F:	drivers/ata/libahci_platform.c
>  F:	include/linux/ahci_platform.h
>  
> +LIBATA SATA AHCI SYNOPSYS DWC CONTROLLER DRIVER
> +M:	Serge Semin <fancer.lancer@gmail.com>
> +L:	linux-ide@vger.kernel.org
> +S:	Maintained
> +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git

Wrong tree. This should be libata tree.

> +F:	Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
> +F:	Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> +F:	drivers/ata/ahci_dwc.c
> +
>  LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
>  M:	Mikael Pettersson <mikpelinux@gmail.com>
>  L:	linux-ide@vger.kernel.org


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
  2022-03-24  0:16 ` [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support Serge Semin
@ 2022-03-24  2:21   ` Damien Le Moal
  2022-04-11 12:41     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  2:21 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe, Serge Semin
  Cc: Alexey Malahov, Pavel Parkhomenko, Rob Herring, linux-ide,
	linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> Synopsys AHCI SATA controller can work pretty under with the generic
> AHCI-platform driver control. But there are vendor-specific peculiarities
> which can tune the device performance up and which may need to be fixed up
> for proper device functioning. In addition some DWC AHCI-based controllers
> may require small platform-specific fixups, so adding them in the generic
> AHCI driver would have ruined the code simplicity. Shortly speaking in
> order to keep the generic AHCI-platform code clean and have DWC AHCI
> SATA-specific features supported we suggest to add a dedicated DWC AHCI
> SATA device driver. Aside with the standard AHCI-platform resources
> getting, enabling/disabling and the controller registration the new driver
> performs the next actions.
> 
> First of all there is a way to verify whether the HBA/ports capabilities
> activated in OF are correct. Almost all features availability is reflected
> in the vendor-specific parameters registers. So the DWC AHCI driver does
> the capabilities sanity check based on the corresponding fields state.
> 
> Secondly if either the Command Completion Coalescing or the Device Sleep
> feature is enabled the DWC AHCI-specific internal 1ms timer must be fixed
> in accordance with the application clock signal frequency. In particular
> the timer value must be set to be Fapp * 1000. Normally the SoC designers
> pre-configure the TIMER1MS register to contain a correct value by default.
> But the platforms can support the application clock rate change. If that
> happens the 1ms timer value must be accordingly updated otherwise the
> dependent features won't work as expected. In the DWC AHCI driver we
> suggest to rely on the "aclk" reference clock rate to set the timer
> interval up. That clock source is supposed to be the AHCI SATA application
> clock in accordance with the DT bindings.
> 
> Finally DWC AHCI SATA controller AXI/AHB bus DMA-engine can be tuned up to
> transfer up to 1024 * FIFO words at a time by setting the Tx/Rx
> transaction size in the DMA control register. The maximum value depends on
> the DMA data bus and AXI/AHB bus maximum burst length. In most of the
> cases it's better to set the maximum possible value to reach the best AHCI
> SATA controller performance. But sometimes in order to improve the system
> interconnect responsiveness, transferring in smaller data chunks may be
> more preferable. For such cases and for the case when the default value
> doesn't provide the best DMA bus performance we suggest to use the new
> HBA-port specific DT-properties "snps,{tx,rx}-ts-max" to tune the DMA
> transactions size up.
> 
> After all the settings denoted above are handled the DWC AHCI SATA driver
> proceeds further with the standard AHCI-platform host initializations.
> 
> Note since DWC AHCI controller is now have a dedicated driver we can
> discard the corresponding compatible string from the ahci-platform.c
> module. The same concerns "snps,spear-ahci" compatible string, which is
> also based on the DWC AHCI IP-core.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> Note there are three more AHCI SATA drivers which have been created for
> the devices based on the DWC AHCI SATA IP-core. It's AHCI SunXi, St and
> iMX drivers. Mostly they don't support the features implemented in this
> driver. So hopefully sometime in future they can be converted to be based
> on the generic DWC AHCI SATA driver and just perform some
> subvendor-specific setups in their own glue-driver code. But for now
> let's leave the generic DWC AHCI SATA code as is. Hopefully the new DWC
> AHCI-based device drivers will try at least to re-use a part of the DWC
> AHCI driver methods if not being able to be integrated in the generic
> DWC driver code.
> ---
>  drivers/ata/Kconfig         |  10 +
>  drivers/ata/Makefile        |   1 +
>  drivers/ata/ahci_dwc.c      | 395 ++++++++++++++++++++++++++++++++++++
>  drivers/ata/ahci_platform.c |   2 -
>  4 files changed, 406 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/ata/ahci_dwc.c
> 
> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> index cb54631fd950..ab11bcf8510c 100644
> --- a/drivers/ata/Kconfig
> +++ b/drivers/ata/Kconfig
> @@ -174,6 +174,16 @@ config AHCI_DM816
>  
>  	  If unsure, say N.
>  
> +config AHCI_DWC
> +	tristate "Synopsys DWC AHCI SATA support"
> +	select SATA_HOST
> +	default SATA_AHCI_PLATFORM
> +	help
> +	  This option enables support for the Synopsys DWC AHCI SATA
> +	  controller implementation.
> +
> +	  If unsure, say N.
> +
>  config AHCI_ST
>  	tristate "ST AHCI SATA support"
>  	depends on ARCH_STI
> diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> index b8aebfb14e82..34623365d9a6 100644
> --- a/drivers/ata/Makefile
> +++ b/drivers/ata/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_DM816)	+= ahci_dm816.o libahci.o libahci_platform.o
> +obj-$(CONFIG_AHCI_DWC)		+= ahci_dwc.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_IMX)		+= ahci_imx.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_MTK)		+= ahci_mtk.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_MVEBU)	+= ahci_mvebu.o libahci.o libahci_platform.o
> diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
> new file mode 100644
> index 000000000000..c51e2251994e
> --- /dev/null
> +++ b/drivers/ata/ahci_dwc.c
> @@ -0,0 +1,395 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * DWC AHCI SATA Platform driver
> + *
> + * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
> + */
> +
> +#include <linux/ahci_platform.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/libata.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm.h>
> +
> +#include "ahci.h"
> +
> +#define DRV_NAME "ahci-dwc"
> +
> +#define DWC_AHCI_FBS_PMPN_MAX		15

The convention is to name things starting with AHCI, e.g. AHCI_DWC_xxxx

> +
> +/* DWC AHCI SATA controller specific registers */
> +#define DWC_AHCI_HOST_OOBR		0xbc
> +#define DWC_AHCI_HOST_OOB_WE		BIT(31)
> +#define DWC_AHCI_HOST_CWMIN_MASK	GENMASK(30, 24)
> +#define DWC_AHCI_HOST_CWMAX_MASK	GENMASK(23, 16)
> +#define DWC_AHCI_HOST_CIMIN_MASK	GENMASK(15, 8)
> +#define DWC_AHCI_HOST_CIMAX_MASK	GENMASK(7, 0)
> +
> +#define DWC_AHCI_HOST_GPCR		0xd0
> +#define DWC_AHCI_HOST_GPSR		0xd4
> +
> +#define DWC_AHCI_HOST_TIMER1MS		0xe0
> +#define DWC_AHCI_HOST_TIMV_MASK		GENMASK(19, 0)
> +
> +#define DWC_AHCI_HOST_GPARAM1R		0xe8
> +#define DWC_AHCI_HOST_ALIGN_M		BIT(31)
> +#define DWC_AHCI_HOST_RX_BUFFER		BIT(30)
> +#define DWC_AHCI_HOST_PHY_DATA_MASK	GENMASK(29, 28)
> +#define DWC_AHCI_HOST_PHY_RST		BIT(27)
> +#define DWC_AHCI_HOST_PHY_CTRL_MASK	GENMASK(26, 21)
> +#define DWC_AHCI_HOST_PHY_STAT_MASK	GENMASK(20, 15)
> +#define DWC_AHCI_HOST_LATCH_M		BIT(14)
> +#define DWC_AHCI_HOST_PHY_TYPE_MASK	GENMASK(13, 11)
> +#define DWC_AHCI_HOST_RET_ERR		BIT(10)
> +#define DWC_AHCI_HOST_AHB_ENDIAN_MASK	GENMASK(9, 8)
> +#define DWC_AHCI_HOST_S_HADDR		BIT(7)
> +#define DWC_AHCI_HOST_M_HADDR		BIT(6)
> +#define DWC_AHCI_HOST_S_HDATA_MASK	GENMASK(5, 3)
> +#define DWC_AHCI_HOST_M_HDATA_MASK	GENMASK(2, 0)
> +
> +#define DWC_AHCI_HOST_GPARAM2R		0xec
> +#define DWC_AHCI_HOST_FBS_MEM_S		BIT(19)
> +#define DWC_AHCI_HOST_FBS_PMPN_MASK	GENMASK(17, 16)
> +#define DWC_AHCI_HOST_FBS_SUP		BIT(15)
> +#define DWC_AHCI_HOST_DEV_CP		BIT(14)
> +#define DWC_AHCI_HOST_DEV_MP		BIT(13)
> +#define DWC_AHCI_HOST_ENCODE_M		BIT(12)
> +#define DWC_AHCI_HOST_RXOOB_CLK_M	BIT(11)
> +#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
> +#define DWC_AHCI_HOST_TXOOB_M		BIT(9)
> +#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
> +#define DWC_AHCI_HOST_RXOOB_CLK_MASK	GENMASK(8, 0)
> +
> +#define DWC_AHCI_HOST_PPARAMR		0xf0
> +#define DWC_AHCI_HOST_TX_MEM_M		BIT(11)
> +#define DWC_AHCI_HOST_TX_MEM_S		BIT(10)
> +#define DWC_AHCI_HOST_RX_MEM_M		BIT(9)
> +#define DWC_AHCI_HOST_RX_MEM_S		BIT(8)
> +#define DWC_AHCI_HOST_TXFIFO_DEPTH	GENMASK(7, 4)
> +#define DWC_AHCI_HOST_RXFIFO_DEPTH	GENMASK(3, 0)
> +
> +#define DWC_AHCI_HOST_TESTR		0xf4
> +#define DWC_AHCI_HOST_PSEL_MASK		GENMASK(18, 16)
> +#define DWC_AHCI_HOST_TEST_IF		BIT(0)
> +
> +#define DWC_AHCI_HOST_VERSIONR		0xf8
> +#define DWC_AHCI_HOST_IDR		0xfc
> +
> +#define DWC_AHCI_PORT_DMACR		0x70
> +#define DWC_AHCI_PORT_RXABL_MASK	GENMASK(15, 12)
> +#define DWC_AHCI_PORT_TXABL_MASK	GENMASK(11, 8)
> +#define DWC_AHCI_PORT_RXTS_MASK		GENMASK(7, 4)
> +#define DWC_AHCI_PORT_TXTS_MASK		GENMASK(3, 0)
> +#define DWC_AHCI_PORT_PHYCR		0x74
> +#define DWC_AHCI_PORT_PHYSR		0x78
> +
> +struct dwc_ahci_host_priv {
> +	struct platform_device *pdev;
> +
> +	u32 timv;
> +	u32 dmacr[AHCI_MAX_PORTS];
> +};
> +
> +static struct ahci_host_priv *dwc_ahci_get_resources(struct platform_device *pdev)

Same: dwc_ahci_get_resources() -> ahci_dwc_get_resources()

> +{
> +	struct dwc_ahci_host_priv *dpriv;
> +	struct ahci_host_priv *hpriv;
> +
> +	dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);
> +	if (!dpriv)
> +		return ERR_PTR(-ENOMEM);
> +
> +	dpriv->pdev = pdev;
> +
> +	hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
> +	if (IS_ERR(hpriv))
> +		return hpriv;
> +
> +	hpriv->plat_data = (void *)dpriv;
> +
> +	return hpriv;
> +}
> +
> +static void dwc_ahci_check_cap(struct ahci_host_priv *hpriv)
> +{
> +	unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
> +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> +	bool dev_mp, dev_cp, fbs_sup;
> +	unsigned int fbs_pmp;
> +	u32 param;
> +	int i;
> +
> +	param = readl(hpriv->mmio + DWC_AHCI_HOST_GPARAM2R);
> +	dev_mp = !!(param & DWC_AHCI_HOST_DEV_MP);
> +	dev_cp = !!(param & DWC_AHCI_HOST_DEV_CP);
> +	fbs_sup = !!(param & DWC_AHCI_HOST_FBS_SUP);
> +	fbs_pmp = 5 * FIELD_GET(DWC_AHCI_HOST_FBS_PMPN_MASK, param);
> +
> +	if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {
> +		dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");
> +		hpriv->saved_cap &= ~HOST_CAP_MPS;
> +	}
> +
> +
> +	if (fbs_sup && fbs_pmp < DWC_AHCI_FBS_PMPN_MAX) {
> +		dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",
> +			 fbs_pmp);
> +	}
> +
> +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> +		if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {
> +			dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;
> +		}
> +
> +		if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {
> +			dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;
> +		}
> +
> +		if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {
> +			dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;
> +		}
> +	}
> +}
> +
> +static void dwc_ahci_init_timer(struct ahci_host_priv *hpriv)
> +{
> +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> +	unsigned long rate;
> +	struct clk *aclk;
> +	u32 cap, cap2;
> +
> +	/* 1ms tick is generated only for the CCC or DevSleep features */
> +	cap = readl(hpriv->mmio + HOST_CAP);
> +	cap2 = readl(hpriv->mmio + HOST_CAP2);
> +	if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))
> +		return;
> +
> +	/*
> +	 * Tick is generated based on the AXI/AHB application clocks signal
> +	 * so we need to be sure in the clock we are going to use.
> +	 */
> +	aclk = ahci_platform_find_clk(hpriv, "aclk");
> +	if (!aclk)
> +		return;
> +
> +	/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */
> +	dpriv->timv = readl(hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> +	dpriv->timv = FIELD_GET(DWC_AHCI_HOST_TIMV_MASK, dpriv->timv);
> +	rate = clk_get_rate(aclk) / 1000UL;
> +	if (rate == dpriv->timv)
> +		return;
> +
> +	dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",
> +		 rate / 1000UL);
> +	dpriv->timv = FIELD_PREP(DWC_AHCI_HOST_TIMV_MASK, rate);
> +	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> +}
> +
> +static int dwc_ahci_init_dmacr(struct ahci_host_priv *hpriv)
> +{
> +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> +	struct device_node *child;
> +	void __iomem *port_mmio;
> +	u32 port, dmacr, ts;
> +
> +	/*
> +	 * Update the DMA Tx/Rx transaction sizes in accordance with the
> +	 * platform setup. Note values exceeding maximal or minimal limits will
> +	 * be automatically clamped. Also note the register isn't affected by
> +	 * the HBA global reset so we can freely initialize it once until the
> +	 * next system reset.
> +	 */
> +	for_each_child_of_node(dpriv->pdev->dev.of_node, child) {
> +		if (!of_device_is_available(child))
> +			continue;
> +
> +		if (of_property_read_u32(child, "reg", &port)) {
> +			of_node_put(child);
> +			return -EINVAL;
> +		}
> +
> +		port_mmio = __ahci_port_base(hpriv, port);
> +		dmacr = readl(port_mmio + DWC_AHCI_PORT_DMACR);
> +
> +		if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
> +			ts = ilog2(ts);
> +			dmacr &= ~DWC_AHCI_PORT_TXTS_MASK;
> +			dmacr |= FIELD_PREP(DWC_AHCI_PORT_TXTS_MASK, ts);
> +		}
> +
> +		if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
> +			ts = ilog2(ts);
> +			dmacr &= ~DWC_AHCI_PORT_RXTS_MASK;
> +			dmacr |= FIELD_PREP(DWC_AHCI_PORT_RXTS_MASK, ts);
> +		}
> +
> +		writel(dmacr, port_mmio + DWC_AHCI_PORT_DMACR);
> +		dpriv->dmacr[port] = dmacr;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dwc_ahci_init_host(struct ahci_host_priv *hpriv)
> +{
> +	int rc;
> +
> +	rc = ahci_platform_enable_resources(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	dwc_ahci_check_cap(hpriv);
> +
> +	dwc_ahci_init_timer(hpriv);
> +
> +	rc = dwc_ahci_init_dmacr(hpriv);
> +	if (rc)
> +		goto err_disable_resources;
> +
> +	return 0;
> +
> +err_disable_resources:
> +	ahci_platform_disable_resources(hpriv);
> +
> +	return rc;
> +}
> +
> +static int dwc_ahci_reinit_host(struct ahci_host_priv *hpriv)
> +{
> +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> +	unsigned long port_map = hpriv->port_map;
> +	void __iomem *port_mmio;
> +	int i, rc;
> +
> +	rc = ahci_platform_enable_resources(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> +
> +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> +		port_mmio = __ahci_port_base(hpriv, i);
> +		writel(dpriv->dmacr[i], port_mmio + DWC_AHCI_PORT_DMACR);
> +	}
> +
> +	return 0;
> +}
> +
> +static void dwc_ahci_clear_host(struct ahci_host_priv *hpriv)
> +{
> +	ahci_platform_disable_resources(hpriv);
> +}
> +
> +static void dwc_ahci_stop_host(struct ata_host *host)
> +{
> +	struct ahci_host_priv *hpriv = host->private_data;
> +
> +	dwc_ahci_clear_host(hpriv);
> +}
> +
> +static struct ata_port_operations dwc_ahci_port_ops = {
> +	.inherits	= &ahci_platform_ops,
> +	.host_stop	= dwc_ahci_stop_host,
> +};
> +
> +static const struct ata_port_info dwc_ahci_port_info = {
> +	.flags		= AHCI_FLAG_COMMON,
> +	.pio_mask	= ATA_PIO4,
> +	.udma_mask	= ATA_UDMA6,
> +	.port_ops	= &dwc_ahci_port_ops,
> +};
> +
> +static struct scsi_host_template dwc_ahci_scsi_info = {
> +	AHCI_SHT(DRV_NAME),
> +};
> +
> +static int dwc_ahci_probe(struct platform_device *pdev)
> +{
> +	struct ahci_host_priv *hpriv;
> +	int rc;
> +
> +	hpriv = dwc_ahci_get_resources(pdev);
> +	if (IS_ERR(hpriv))
> +		return PTR_ERR(hpriv);
> +
> +	rc = dwc_ahci_init_host(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	rc = ahci_platform_init_host(pdev, hpriv, &dwc_ahci_port_info,
> +				     &dwc_ahci_scsi_info);
> +	if (rc)
> +		goto err_clear_host;
> +
> +	return 0;
> +
> +err_clear_host:
> +	dwc_ahci_clear_host(hpriv);
> +
> +	return rc;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int dwc_ahci_suspend(struct device *dev)
> +{
> +	struct ata_host *host = dev_get_drvdata(dev);
> +	struct ahci_host_priv *hpriv = host->private_data;
> +	int rc;
> +
> +	rc = ahci_platform_suspend_host(dev);
> +	if (rc)
> +		return rc;
> +
> +	dwc_ahci_clear_host(hpriv);
> +
> +	return 0;
> +}
> +
> +static int dwc_ahci_resume(struct device *dev)
> +{
> +	struct ata_host *host = dev_get_drvdata(dev);
> +	struct ahci_host_priv *hpriv = host->private_data;
> +	int rc;
> +
> +	rc = dwc_ahci_reinit_host(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	return ahci_platform_resume_host(dev);
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(dwc_ahci_pm_ops, dwc_ahci_suspend, dwc_ahci_resume);
> +
> +static const struct of_device_id dwc_ahci_of_match[] = {
> +	{ .compatible = "snps,dwc-ahci", },
> +	{ .compatible = "snps,spear-ahci", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, dwc_ahci_of_match);
> +
> +static struct platform_driver dwc_ahci_driver = {
> +	.probe = dwc_ahci_probe,
> +	.remove = ata_platform_remove_one,
> +	.shutdown = ahci_platform_shutdown,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = dwc_ahci_of_match,
> +		.pm = &dwc_ahci_pm_ops,
> +	},
> +};
> +module_platform_driver(dwc_ahci_driver);
> +
> +MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
> +MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
> index 24c25f076f37..052eaa30d262 100644
> --- a/drivers/ata/ahci_platform.c
> +++ b/drivers/ata/ahci_platform.c
> @@ -80,9 +80,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
>  static const struct of_device_id ahci_of_match[] = {
>  	{ .compatible = "generic-ahci", },
>  	/* Keep the following compatibles for device tree compatibility */
> -	{ .compatible = "snps,spear-ahci", },
>  	{ .compatible = "ibm,476gtr-ahci", },
> -	{ .compatible = "snps,dwc-ahci", },
>  	{ .compatible = "hisilicon,hisi-ahci", },
>  	{ .compatible = "cavium,octeon-7130-ahci", },
>  	{},


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number
  2022-03-24  1:40   ` Damien Le Moal
@ 2022-03-24  8:12     ` Sergey Shtylyov
  2022-03-24  8:13       ` Damien Le Moal
  0 siblings, 1 reply; 65+ messages in thread
From: Sergey Shtylyov @ 2022-03-24  8:12 UTC (permalink / raw)
  To: Damien Le Moal, Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 4:40 AM, Damien Le Moal wrote:

>> Having greater than (AHCI_MAX_PORTS = 32) ports detected isn't that
>> critical from the further AHCI-platform initialization point of view since
>> exceeding the ports upper limit will cause allocating more resources than
>> will be used afterwards. But detecting too many child DT-nodes doesn't
>> seem right since it's very unlikely to have it on an ordinary platform. In
>> accordance with the AHCI specification there can't be more than 32 ports
>> implemented at least due to having the CAP.NP field of 4 bits wide and the
>> PI register of dword size. Thus if such situation is found the DTB must
>> have been corrupted and the data read from it shouldn't be reliable. Let's
>> consider that as an erroneous situation and halt further resources
>> allocation.
>>
>> Note it's logically more correct to have the nports set only after the
>> initialization value is checked for being sane. So while at it let's make
>> sure nports is assigned with a correct value.
>>
>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
>> ---
>>  drivers/ata/libahci_platform.c | 16 +++++++++++-----
>>  1 file changed, 11 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
>> index 4fb9629c03ab..845042295b97 100644
>> --- a/drivers/ata/libahci_platform.c
>> +++ b/drivers/ata/libahci_platform.c
>> @@ -470,15 +470,21 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>>  		}
>>  	}
>>  
>> -	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
>> -
>>  	/*
>> -	 * If no sub-node was found, we still need to set nports to
>> -	 * one in order to be able to use the
>> +	 * Too many sub-nodes most likely means having something wrong with
>> +	 * firmware. If no sub-node was found, we still need to set nports
>> +	 * to one in order to be able to use the
>>  	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
>>  	 */
>> -	if (!child_nodes)
>> +	child_nodes = of_get_child_count(dev->of_node);
>> +	if (child_nodes > AHCI_MAX_PORTS) {
>> +		rc = -EINVAL;
>> +		goto err_out;
>> +	} else if (!child_nodes) {
> 
> No need for "else" after a return.

   You meant *goto*? :-)

[...]

MBR, Sergey

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

* Re: [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number
  2022-03-24  8:12     ` Sergey Shtylyov
@ 2022-03-24  8:13       ` Damien Le Moal
  2022-04-11 13:10         ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-24  8:13 UTC (permalink / raw)
  To: Sergey Shtylyov, Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 17:12, Sergey Shtylyov wrote:
> On 3/24/22 4:40 AM, Damien Le Moal wrote:
> 
>>> Having greater than (AHCI_MAX_PORTS = 32) ports detected isn't that
>>> critical from the further AHCI-platform initialization point of view since
>>> exceeding the ports upper limit will cause allocating more resources than
>>> will be used afterwards. But detecting too many child DT-nodes doesn't
>>> seem right since it's very unlikely to have it on an ordinary platform. In
>>> accordance with the AHCI specification there can't be more than 32 ports
>>> implemented at least due to having the CAP.NP field of 4 bits wide and the
>>> PI register of dword size. Thus if such situation is found the DTB must
>>> have been corrupted and the data read from it shouldn't be reliable. Let's
>>> consider that as an erroneous situation and halt further resources
>>> allocation.
>>>
>>> Note it's logically more correct to have the nports set only after the
>>> initialization value is checked for being sane. So while at it let's make
>>> sure nports is assigned with a correct value.
>>>
>>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
>>> ---
>>>  drivers/ata/libahci_platform.c | 16 +++++++++++-----
>>>  1 file changed, 11 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
>>> index 4fb9629c03ab..845042295b97 100644
>>> --- a/drivers/ata/libahci_platform.c
>>> +++ b/drivers/ata/libahci_platform.c
>>> @@ -470,15 +470,21 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>>>  		}
>>>  	}
>>>  
>>> -	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
>>> -
>>>  	/*
>>> -	 * If no sub-node was found, we still need to set nports to
>>> -	 * one in order to be able to use the
>>> +	 * Too many sub-nodes most likely means having something wrong with
>>> +	 * firmware. If no sub-node was found, we still need to set nports
>>> +	 * to one in order to be able to use the
>>>  	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
>>>  	 */
>>> -	if (!child_nodes)
>>> +	child_nodes = of_get_child_count(dev->of_node);
>>> +	if (child_nodes > AHCI_MAX_PORTS) {
>>> +		rc = -EINVAL;
>>> +		goto err_out;
>>> +	} else if (!child_nodes) {
>>
>> No need for "else" after a return.
> 
>    You meant *goto*? :-)

Yes :) No need for the else after goto.

> 
> [...]
> 
> MBR, Sergey


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-24  0:58   ` Damien Le Moal
@ 2022-03-24 21:37     ` Serge Semin
  2022-03-25  1:56       ` Damien Le Moal
  0 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-03-24 21:37 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

Hello Damien

On Thu, Mar 24, 2022 at 09:58:34AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > It's better for readability and maintainability to explicitly assign an
> > error number to the variable used then as a return value from the method
> > on the cleanup-on-error path. So adding new code in the method we won't
> 

> No it is not. On-stack variable initialization is not free. So if
> initializing the variable is not needed, do not do it.

This patch isn't about on-stack initialization, but about bringing an
order to the error-handling procedure of the
ahci_platform_get_resources() method. Explicitly setting the rc variable
with an error value closer to the place caused the error much easier
to perceive than keeping in mind that the variable has been set with
some default value. That turns to be even more justified seeing the
rest of the method does it that way.

See my next comment regarding the initialization.

> 
> > have to think whether the overridden rc-variable is set afterward in case
> > of an error. Saving one line of code doesn't worth it especially seeing
> > the rest of the ahci_platform_get_resources() function errors handling
> > blocks do explicitly write errno to rc.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/libahci_platform.c | 6 ++++--
> >  1 file changed, 4 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index 18296443ccba..1bd2f1686239 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  	struct ahci_host_priv *hpriv;
> >  	struct clk *clk;
> >  	struct device_node *child;
> > -	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
> > +	int i, enabled_ports = 0, rc = 0, child_nodes;
> >  	u32 mask_port_map = 0;
> >  
> >  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> > @@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  
> >  	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
> >  			     GFP_KERNEL);
> > -	if (!hpriv)
> > +	if (!hpriv) {
> > +		rc = -ENOMEM;
> >  		goto err_out;
> > +	}
> 

> If you set rc to -ENOMEM here, then the 0 initialization of rc is not needed.

Normally you are right. But the case of the rc/ret/etc variables is
special. I'd stick with having it defaulted to 0 here. Here is why.

When it comes to using the rc/ret/etc variables the maintainability
gets to be more important than some small optimization (especially
here seeing the ahci_platform_get_resources() is called once per
device life-time) because in case of the method alteration these
variables very often get to be involved in one way or another. If due
to a mistake the rc/ret/etc variable isn't updated in case of an
erroneous situation but the method is terminated with the goto-pattern
and rc/ret/etc isn't initialized with any default value then we will
end up with having a garbage pointer returned. We'd be lucky if it was
a null pointer, but in general it can be a reference to some random
memory region. In the later case the kernel may experience random
crashes with hard-to-find cause of the problem. In the former case the
problem would have been tracked right away on the testing stage by
getting the system invalid-pointer de-reference crash. That's why
defaulting the variable to zero here is still useful.

-Sergey

> 
> >  
> >  	devres_add(dev, hpriv);
> >  
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-24 21:37     ` Serge Semin
@ 2022-03-25  1:56       ` Damien Le Moal
  2022-04-06 20:03         ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-25  1:56 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On 2022/03/25 6:37, Serge Semin wrote:
> Hello Damien
> 
> On Thu, Mar 24, 2022 at 09:58:34AM +0900, Damien Le Moal wrote:
>> On 3/24/22 09:16, Serge Semin wrote:
>>> It's better for readability and maintainability to explicitly assign an
>>> error number to the variable used then as a return value from the method
>>> on the cleanup-on-error path. So adding new code in the method we won't
>>
> 
>> No it is not. On-stack variable initialization is not free. So if
>> initializing the variable is not needed, do not do it.
> 
> This patch isn't about on-stack initialization, but about bringing an
> order to the error-handling procedure of the
> ahci_platform_get_resources() method. Explicitly setting the rc variable
> with an error value closer to the place caused the error much easier
> to perceive than keeping in mind that the variable has been set with
> some default value. That turns to be even more justified seeing the
> rest of the method does it that way.

I agree with that change. Setting "rc = -ENOMEM" under the "if" checking for
error is fine.

> 
> See my next comment regarding the initialization.
> 
>>
>>> have to think whether the overridden rc-variable is set afterward in case
>>> of an error. Saving one line of code doesn't worth it especially seeing
>>> the rest of the ahci_platform_get_resources() function errors handling
>>> blocks do explicitly write errno to rc.
>>>
>>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
>>> ---
>>>  drivers/ata/libahci_platform.c | 6 ++++--
>>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
>>> index 18296443ccba..1bd2f1686239 100644
>>> --- a/drivers/ata/libahci_platform.c
>>> +++ b/drivers/ata/libahci_platform.c
>>> @@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>>>  	struct ahci_host_priv *hpriv;
>>>  	struct clk *clk;
>>>  	struct device_node *child;
>>> -	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
>>> +	int i, enabled_ports = 0, rc = 0, child_nodes;
>>>  	u32 mask_port_map = 0;
>>>  
>>>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
>>> @@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>>>  
>>>  	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
>>>  			     GFP_KERNEL);
>>> -	if (!hpriv)
>>> +	if (!hpriv) {
>>> +		rc = -ENOMEM;
>>>  		goto err_out;
>>> +	}
>>
> 
>> If you set rc to -ENOMEM here, then the 0 initialization of rc is not needed.
> 
> Normally you are right. But the case of the rc/ret/etc variables is
> special. I'd stick with having it defaulted to 0 here. Here is why.
> 
> When it comes to using the rc/ret/etc variables the maintainability
> gets to be more important than some small optimization (especially
> here seeing the ahci_platform_get_resources() is called once per
> device life-time) because in case of the method alteration these
> variables very often get to be involved in one way or another. If due
> to a mistake the rc/ret/etc variable isn't updated in case of an
> erroneous situation but the method is terminated with the goto-pattern
> and rc/ret/etc isn't initialized with any default value then we will
> end up with having a garbage pointer returned. We'd be lucky if it was
> a null pointer, but in general it can be a reference to some random
> memory region. In the later case the kernel may experience random
> crashes with hard-to-find cause of the problem. In the former case the
> problem would have been tracked right away on the testing stage by
> getting the system invalid-pointer de-reference crash. That's why
> defaulting the variable to zero here is still useful.

No it is not. We have code reviews and testing to catch mistakes. If we start
thinking along these lines, any useless local variable initialization can be
justified. So let's not go there please.


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema
  2022-03-24  0:16 ` [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema Serge Semin
@ 2022-03-28 19:32   ` Rob Herring
  2022-04-11 19:34     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Rob Herring @ 2022-03-28 19:32 UTC (permalink / raw)
  To: Serge Semin
  Cc: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin,
	Alexey Malahov, Pavel Parkhomenko,
	open list:LIBATA SUBSYSTEM (Serial and Parallel ATA drivers),
	linux-kernel, devicetree

On Wed, Mar 23, 2022 at 7:16 PM Serge Semin
<Sergey.Semin@baikalelectronics.ru> wrote:
>
> Currently the DT bindings of Generic AHCI Controllers are described by
> means of the legacy text file. Since such format is deprecated in favor of
> the DT schema. Let's convert the Generic AHCI Controllers bindings file
> then to the corresponding yaml files. There will be two of them: a DT
> schema with a set of properties applied to all AHCI-compatible devices,
> and a DT schema validating an AHCI-controller on a generic platform. So if
> a controller conforms to the Serial ATA AHCI interface specification with
> just peculiar platform environment settings like clock sources, PHYs,
> power regulators or resets, then the generic AHCI bindings should work for
> it. Otherwise a dedicated DT-schema needs to be created.
>
> So a common AHCI SATA controller DT-node is supposed to be equipped with
> at least compatible, reg and interrupts properties. It can optionally
> contain clocks, resets, {ahci,target,phy}-supply and phys phandles. In
> addition the property "ports-implemented" can be specified in order to
> define the number of implemented SATA ports. An AHCI SATA controller
> DT-node can also have a set of sub-nodes representing its ports, for each
> of which an individual power source and PHY phandle can be specified.
>
> Note we have omitted the next compatible strings
> "marvell,armada-380-ahci", "marvell,armada-3700-ahci", "snps,dwc-ahci",
> "snps,spear-ahci" since the corresponding controllers are handled by the
> dedicated drivers now, thus are supposed to have their own DT-schema
> defined. dma-coherent has also been discarded since it's a generic
> property and is evaluated by the dt-schema parser.
>
> Also note that if there is the "reg-names" property specified for a AHCI
> DT-node then it is supposed to at least have the "ahci" sub-string as an
> indicator of the AHCI-compatible registers space.
>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../devicetree/bindings/ata/ahci-common.yaml  | 110 ++++++++++++++++++
>  .../devicetree/bindings/ata/ahci-platform.txt |  79 -------------
>  .../devicetree/bindings/ata/generic-ahci.yaml |  89 ++++++++++++++
>  3 files changed, 199 insertions(+), 79 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
>  delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
>  create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml

This has already been converted and is in Linus' tree now for v5.18.

Rob

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

* Re: [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support
  2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
                   ` (20 preceding siblings ...)
  2022-03-24  0:16 ` [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver Serge Semin
@ 2022-03-28 20:06 ` Damien Le Moal
  2022-03-29  8:30   ` Damien Le Moal
  21 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-28 20:06 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
[...]
> After the denoted above functionality is added we can finally introduce
> the Baikal-T1 AHCI SATA controller support into the DWC AHCI SATA driver.
> The controller is based on the DWC AHCI SATA IP-core v4.10a and can work
> well with the generic DWC AHCI driver. The only peculiarity of it is
> connected with the SATA Ports reference clock source. It can be supplied
> either from the internal SoC PLL or from the chip pads. Currently we have
> to prefer selecting the signal coming from the pads if the corresponding
> clock source is specified because the link doesn't get stably established
> when the internal clock signal is activated. In addition the platform has
> trigger-based reset signals so the corresponding flag must be passed to
> the generic AHCI-resource getter.
> 

I am assuming this is "v2" of your patches. Please add this version number
to your patch titles ("[PATCH v2]") and add a changelog here in the cover
letter.

> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-ide@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: devicetree@vger.kernel.org
> 
> Serge Semin (21):
>   dt-bindings: ata: sata: Extend number of SATA ports
>   dt-bindings: ata: Convert AHCI-bindings to DT schema
>   ata: libahci_platform: Explicitly set rc on devres_alloc failure
>   ata: libahci_platform: Convert to using handy devm-ioremap methods
>   ata: libahci_platform: Convert to using devm bulk clocks API
>   ata: libahci_platform: Add function returning a clock-handle by id
>   ata: libahci_platform: Sanity check the DT child nodes number
>   ata: libahci_platform: Parse ports-implemented property in resources
>     getter
>   ata: libahci_platform: Introduce reset assertion/deassertion methods
>   dt-bindings: ata: ahci: Add platform capability properties
>   ata: libahci: Extend port-cmd flags set with port capabilities
>   ata: libahci: Discard redundant force_port_map parameter
>   ata: libahci: Don't read AHCI version twice in the save-config method
>   ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
>   ata: ahci: Introduce firmware-specific caps initialization
>   dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
>   ata: ahci: Add DWC AHCI SATA controller support
>   dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
>   ata: ahci-dwc: Add platform-specific quirks support
>   ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
>   MAINTAINERS: Add maintainers for DWC AHCI SATA driver
> 
>  .../devicetree/bindings/ata/ahci-common.yaml  | 176 ++++++
>  .../devicetree/bindings/ata/ahci-platform.txt |  79 ---
>  .../bindings/ata/baikal,bt1-ahci.yaml         | 132 +++++
>  .../devicetree/bindings/ata/generic-ahci.yaml |  98 ++++
>  .../devicetree/bindings/ata/sata-common.yaml  |   7 +-
>  .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++
>  MAINTAINERS                                   |   9 +
>  drivers/ata/Kconfig                           |  11 +
>  drivers/ata/Makefile                          |   1 +
>  drivers/ata/ahci.c                            |   4 +-
>  drivers/ata/ahci.h                            |  21 +-
>  drivers/ata/ahci_dwc.c                        | 525 ++++++++++++++++++
>  drivers/ata/ahci_mtk.c                        |   2 -
>  drivers/ata/ahci_platform.c                   |   5 -
>  drivers/ata/ahci_st.c                         |   3 -
>  drivers/ata/libahci.c                         |  63 ++-
>  drivers/ata/libahci_platform.c                | 234 +++++---
>  include/linux/ahci_platform.h                 |   8 +-
>  18 files changed, 1321 insertions(+), 178 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
>  delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
>  create mode 100644 Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
>  create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml
>  create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
>  create mode 100644 drivers/ata/ahci_dwc.c
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
  2022-03-24  1:29   ` Damien Le Moal
@ 2022-03-28 22:36   ` kernel test robot
  2022-03-28 23:42   ` kernel test robot
  2022-03-29  0:03   ` kernel test robot
  3 siblings, 0 replies; 65+ messages in thread
From: kernel test robot @ 2022-03-28 22:36 UTC (permalink / raw)
  To: Serge Semin, Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: llvm, kbuild-all, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Hi Serge,

I love your patch! Yet something to improve:

[auto build test ERROR on v5.17]
[also build test ERROR on next-20220328]
[cannot apply to axboe-block/for-next robh/for-next linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
base:    f443e374ae131c168a065ea1748feac6b2e76613
config: arm-buildonly-randconfig-r005-20220327 (https://download.01.org/0day-ci/archive/20220329/202203290643.0ExdJphD-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0f6d9501cf49ce02937099350d08f20c4af86f3d)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/intel-lab-lkp/linux/commit/28cf1dcfb31bfca35af403a8774d0d880923fab3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
        git checkout 28cf1dcfb31bfca35af403a8774d0d880923fab3
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/ata/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/ata/ahci_dm816.c:72:6: error: invalid argument type 'struct clk_bulk_data' to unary expression
           if (!hpriv->clks[1]) {
               ^~~~~~~~~~~~~~~
>> drivers/ata/ahci_dm816.c:77:29: error: passing 'struct clk_bulk_data' to parameter of incompatible type 'struct clk *'
           refclk_rate = clk_get_rate(hpriv->clks[1]);
                                      ^~~~~~~~~~~~~~
   include/linux/clk.h:584:40: note: passing argument to parameter 'clk' here
   unsigned long clk_get_rate(struct clk *clk);
                                          ^
   2 errors generated.


vim +72 drivers/ata/ahci_dm816.c

df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   60  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   61  static int ahci_dm816_phy_init(struct ahci_host_priv *hpriv, struct device *dev)
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   62  {
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   63  	unsigned long refclk_rate;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   64  	int mpy;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   65  	u32 val;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   66  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   67  	/*
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   68  	 * We should have been supplied two clocks: the functional and
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   69  	 * keep-alive clock and the external reference clock. We need the
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   70  	 * rate of the latter to calculate the correct value of MPY bits.
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   71  	 */
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14  @72  	if (!hpriv->clks[1]) {
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   73  		dev_err(dev, "reference clock not supplied\n");
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   74  		return -EINVAL;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   75  	}
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   76  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14  @77  	refclk_rate = clk_get_rate(hpriv->clks[1]);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   78  	if ((refclk_rate % 100) != 0) {
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   79  		dev_err(dev, "reference clock rate must be divisible by 100\n");
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   80  		return -EINVAL;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   81  	}
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   82  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   83  	mpy = ahci_dm816_get_mpy_bits(refclk_rate);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   84  	if (mpy < 0) {
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   85  		dev_err(dev, "can't calculate the MPY bits value\n");
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   86  		return -EINVAL;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   87  	}
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   88  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   89  	/* Enable the PHY and configure the first HBA port. */
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   90  	val = AHCI_DM816_PHY_MPY(mpy) | AHCI_DM816_PHY_LOS(1) |
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   91  	      AHCI_DM816_PHY_RXCDR(4) | AHCI_DM816_PHY_RXEQ(1) |
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   92  	      AHCI_DM816_PHY_TXSWING(3) | AHCI_DM816_PHY_ENPLL(1);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   93  	writel(val, hpriv->mmio + AHCI_DM816_P0PHYCR_REG);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   94  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   95  	/* Configure the second HBA port. */
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   96  	val = AHCI_DM816_PHY_LOS(1) | AHCI_DM816_PHY_RXCDR(4) |
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   97  	      AHCI_DM816_PHY_RXEQ(1) | AHCI_DM816_PHY_TXSWING(3);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   98  	writel(val, hpriv->mmio + AHCI_DM816_P1PHYCR_REG);
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14   99  
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14  100  	return 0;
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14  101  }
df46e6a4c06c89 Bartosz Golaszewski 2017-03-14  102  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

* Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
  2022-03-24  1:29   ` Damien Le Moal
  2022-03-28 22:36   ` kernel test robot
@ 2022-03-28 23:42   ` kernel test robot
  2022-03-29  0:03   ` kernel test robot
  3 siblings, 0 replies; 65+ messages in thread
From: kernel test robot @ 2022-03-28 23:42 UTC (permalink / raw)
  To: Serge Semin, Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: kbuild-all, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Hi Serge,

I love your patch! Yet something to improve:

[auto build test ERROR on v5.17]
[also build test ERROR on next-20220328]
[cannot apply to axboe-block/for-next robh/for-next linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
base:    f443e374ae131c168a065ea1748feac6b2e76613
config: alpha-randconfig-r034-20220327 (https://download.01.org/0day-ci/archive/20220329/202203290730.f6OTgSOz-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/28cf1dcfb31bfca35af403a8774d0d880923fab3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
        git checkout 28cf1dcfb31bfca35af403a8774d0d880923fab3
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=alpha SHELL=/bin/bash drivers/ata/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/ata/ahci_da850.c: In function 'ahci_da850_probe':
>> drivers/ata/ahci_da850.c:181:13: error: wrong type argument to unary exclamation mark
     181 |         if (!hpriv->clks[0]) {
         |             ^
>> drivers/ata/ahci_da850.c:186:34: error: incompatible types when assigning to type 'struct clk_bulk_data' from type 'struct clk *'
     186 |                 hpriv->clks[0] = clk;
         |                                  ^~~
   drivers/ata/ahci_da850.c:194:13: error: wrong type argument to unary exclamation mark
     194 |         if (!hpriv->clks[1]) {
         |             ^
   drivers/ata/ahci_da850.c:201:34: error: incompatible types when assigning to type 'struct clk_bulk_data' from type 'struct clk *'
     201 |                 hpriv->clks[1] = clk;
         |                                  ^~~
>> drivers/ata/ahci_da850.c:204:64: error: incompatible type for argument 1 of 'clk_get_rate'
     204 |         mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
         |                                                     ~~~~~~~~~~~^~~
         |                                                                |
         |                                                                struct clk_bulk_data
   In file included from drivers/ata/ahci.h:23,
                    from drivers/ata/ahci_da850.c:13:
   include/linux/clk.h:880:54: note: expected 'struct clk *' but argument is of type 'struct clk_bulk_data'
     880 | static inline unsigned long clk_get_rate(struct clk *clk)
         |                                          ~~~~~~~~~~~~^~~
--
   drivers/ata/ahci_dm816.c: In function 'ahci_dm816_phy_init':
>> drivers/ata/ahci_dm816.c:72:13: error: wrong type argument to unary exclamation mark
      72 |         if (!hpriv->clks[1]) {
         |             ^
>> drivers/ata/ahci_dm816.c:77:47: error: incompatible type for argument 1 of 'clk_get_rate'
      77 |         refclk_rate = clk_get_rate(hpriv->clks[1]);
         |                                    ~~~~~~~~~~~^~~
         |                                               |
         |                                               struct clk_bulk_data
   In file included from drivers/ata/ahci.h:23,
                    from drivers/ata/ahci_dm816.c:16:
   include/linux/clk.h:880:54: note: expected 'struct clk *' but argument is of type 'struct clk_bulk_data'
     880 | static inline unsigned long clk_get_rate(struct clk *clk)
         |                                          ~~~~~~~~~~~~^~~


vim +186 drivers/ata/ahci_da850.c

018d5ef2048fca Akinobu Mita              2015-01-29  159  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  160  static int ahci_da850_probe(struct platform_device *pdev)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  161  {
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  162  	struct device *dev = &pdev->dev;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  163  	struct ahci_host_priv *hpriv;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  164  	void __iomem *pwrdn_reg;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  165  	struct resource *res;
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  166  	struct clk *clk;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  167  	u32 mpy;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  168  	int rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  169  
16af2d65842d34 Kunihiko Hayashi          2018-08-22  170  	hpriv = ahci_platform_get_resources(pdev, 0);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  171  	if (IS_ERR(hpriv))
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  172  		return PTR_ERR(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  173  
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  174  	/*
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  175  	 * Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  176  	 * when trying to obtain the functional clock. This SATA controller
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  177  	 * uses two clocks for which we specify two connection ids. If we don't
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  178  	 * have the functional clock at this point - call clk_get() again with
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  179  	 * con_id = "fck".
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  180  	 */
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30 @181  	if (!hpriv->clks[0]) {
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  182  		clk = clk_get(dev, "fck");
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  183  		if (IS_ERR(clk))
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  184  			return PTR_ERR(clk);
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  185  
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30 @186  		hpriv->clks[0] = clk;
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  187  	}
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  188  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  189  	/*
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  190  	 * The second clock used by ahci-da850 is the external REFCLK. If we
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  191  	 * didn't get it from ahci_platform_get_resources(), let's try to
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  192  	 * specify the con_id in clk_get().
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  193  	 */
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  194  	if (!hpriv->clks[1]) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  195  		clk = clk_get(dev, "refclk");
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  196  		if (IS_ERR(clk)) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  197  			dev_err(dev, "unable to obtain the reference clock");
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  198  			return -ENODEV;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  199  		}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  200  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  201  		hpriv->clks[1] = clk;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  202  	}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  203  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30 @204  	mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  205  	if (mpy == 0) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  206  		dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  207  		return -EINVAL;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  208  	}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  209  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  210  	rc = ahci_platform_enable_resources(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  211  	if (rc)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  212  		return rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  213  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  214  	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
c88c094985ad38 Christophe JAILLET        2017-08-16  215  	if (!res) {
c88c094985ad38 Christophe JAILLET        2017-08-16  216  		rc = -ENODEV;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  217  		goto disable_resources;
c88c094985ad38 Christophe JAILLET        2017-08-16  218  	}
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  219  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  220  	pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
c88c094985ad38 Christophe JAILLET        2017-08-16  221  	if (!pwrdn_reg) {
c88c094985ad38 Christophe JAILLET        2017-08-16  222  		rc = -ENOMEM;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  223  		goto disable_resources;
c88c094985ad38 Christophe JAILLET        2017-08-16  224  	}
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  225  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  226  	da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  227  
018d5ef2048fca Akinobu Mita              2015-01-29  228  	rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
018d5ef2048fca Akinobu Mita              2015-01-29  229  				     &ahci_platform_sht);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  230  	if (rc)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  231  		goto disable_resources;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  232  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  233  	return 0;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  234  disable_resources:
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  235  	ahci_platform_disable_resources(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  236  	return rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  237  }
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  238  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

* Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
                     ` (2 preceding siblings ...)
  2022-03-28 23:42   ` kernel test robot
@ 2022-03-29  0:03   ` kernel test robot
  3 siblings, 0 replies; 65+ messages in thread
From: kernel test robot @ 2022-03-29  0:03 UTC (permalink / raw)
  To: Serge Semin, Damien Le Moal, Hans de Goede, Jens Axboe
  Cc: llvm, kbuild-all, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Hi Serge,

I love your patch! Yet something to improve:

[auto build test ERROR on v5.17]
[also build test ERROR on next-20220328]
[cannot apply to axboe-block/for-next robh/for-next linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
base:    f443e374ae131c168a065ea1748feac6b2e76613
config: arm-randconfig-r015-20220327 (https://download.01.org/0day-ci/archive/20220329/202203290752.NKWGfglB-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0f6d9501cf49ce02937099350d08f20c4af86f3d)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/intel-lab-lkp/linux/commit/28cf1dcfb31bfca35af403a8774d0d880923fab3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Serge-Semin/ata-ahci-Add-DWC-Baikal-T1-AHCI-SATA-support/20220328-234809
        git checkout 28cf1dcfb31bfca35af403a8774d0d880923fab3
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/ata/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/ata/ahci_da850.c:181:6: error: invalid argument type 'struct clk_bulk_data' to unary expression
           if (!hpriv->clks[0]) {
               ^~~~~~~~~~~~~~~
>> drivers/ata/ahci_da850.c:186:18: error: assigning to 'struct clk_bulk_data' from incompatible type 'struct clk *'
                   hpriv->clks[0] = clk;
                                  ^ ~~~
   drivers/ata/ahci_da850.c:194:6: error: invalid argument type 'struct clk_bulk_data' to unary expression
           if (!hpriv->clks[1]) {
               ^~~~~~~~~~~~~~~
   drivers/ata/ahci_da850.c:201:18: error: assigning to 'struct clk_bulk_data' from incompatible type 'struct clk *'
                   hpriv->clks[1] = clk;
                                  ^ ~~~
>> drivers/ata/ahci_da850.c:204:46: error: passing 'struct clk_bulk_data' to parameter of incompatible type 'struct clk *'
           mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
                                                       ^~~~~~~~~~~~~~
   include/linux/clk.h:880:54: note: passing argument to parameter 'clk' here
   static inline unsigned long clk_get_rate(struct clk *clk)
                                                        ^
   5 errors generated.


vim +181 drivers/ata/ahci_da850.c

018d5ef2048fca Akinobu Mita              2015-01-29  159  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  160  static int ahci_da850_probe(struct platform_device *pdev)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  161  {
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  162  	struct device *dev = &pdev->dev;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  163  	struct ahci_host_priv *hpriv;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  164  	void __iomem *pwrdn_reg;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  165  	struct resource *res;
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  166  	struct clk *clk;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  167  	u32 mpy;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  168  	int rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  169  
16af2d65842d34 Kunihiko Hayashi          2018-08-22  170  	hpriv = ahci_platform_get_resources(pdev, 0);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  171  	if (IS_ERR(hpriv))
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  172  		return PTR_ERR(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  173  
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  174  	/*
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  175  	 * Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  176  	 * when trying to obtain the functional clock. This SATA controller
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  177  	 * uses two clocks for which we specify two connection ids. If we don't
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  178  	 * have the functional clock at this point - call clk_get() again with
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  179  	 * con_id = "fck".
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  180  	 */
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30 @181  	if (!hpriv->clks[0]) {
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  182  		clk = clk_get(dev, "fck");
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  183  		if (IS_ERR(clk))
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  184  			return PTR_ERR(clk);
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  185  
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30 @186  		hpriv->clks[0] = clk;
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  187  	}
82dbe1a68fd65a Bartosz Golaszewski       2017-01-30  188  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  189  	/*
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  190  	 * The second clock used by ahci-da850 is the external REFCLK. If we
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  191  	 * didn't get it from ahci_platform_get_resources(), let's try to
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  192  	 * specify the con_id in clk_get().
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  193  	 */
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  194  	if (!hpriv->clks[1]) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  195  		clk = clk_get(dev, "refclk");
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  196  		if (IS_ERR(clk)) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  197  			dev_err(dev, "unable to obtain the reference clock");
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  198  			return -ENODEV;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  199  		}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  200  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  201  		hpriv->clks[1] = clk;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  202  	}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  203  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30 @204  	mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  205  	if (mpy == 0) {
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  206  		dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  207  		return -EINVAL;
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  208  	}
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  209  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  210  	rc = ahci_platform_enable_resources(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  211  	if (rc)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  212  		return rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  213  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  214  	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
c88c094985ad38 Christophe JAILLET        2017-08-16  215  	if (!res) {
c88c094985ad38 Christophe JAILLET        2017-08-16  216  		rc = -ENODEV;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  217  		goto disable_resources;
c88c094985ad38 Christophe JAILLET        2017-08-16  218  	}
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  219  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  220  	pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
c88c094985ad38 Christophe JAILLET        2017-08-16  221  	if (!pwrdn_reg) {
c88c094985ad38 Christophe JAILLET        2017-08-16  222  		rc = -ENOMEM;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  223  		goto disable_resources;
c88c094985ad38 Christophe JAILLET        2017-08-16  224  	}
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  225  
cdf0ead3747200 Bartosz Golaszewski       2017-01-30  226  	da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  227  
018d5ef2048fca Akinobu Mita              2015-01-29  228  	rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
018d5ef2048fca Akinobu Mita              2015-01-29  229  				     &ahci_platform_sht);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  230  	if (rc)
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  231  		goto disable_resources;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  232  
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  233  	return 0;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  234  disable_resources:
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  235  	ahci_platform_disable_resources(hpriv);
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  236  	return rc;
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  237  }
ae8723f8a9c8e8 Bartlomiej Zolnierkiewicz 2014-03-25  238  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

* Re: [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports
  2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
@ 2022-03-29  8:15   ` Damien Le Moal
  2022-04-11 19:25     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-29  8:15 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe, Rob Herring, Linus Walleij
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, linux-ide,
	linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> The denoted in the description upper limit only concerns the Port
> Multipliers, but not the actual SATA ports. It's an external device
> attached to a SATA port in order to access more than one SATA-drive. So
> when it's attached to a SATA port it just extends the port capability
> while the number of actual SATA ports stays the same. For instance on AHCI
> controllers the number of actual ports is determined by the CAP.NP field
> and the PI (Ports Implemented) register. AFAICS in general the maximum
> number of SATA ports depends on the particular controller implementation.
> Generic AHCI controller can't have more than 32 ports (since CAP.NP is of
> 5 bits wide and PI register is 32-bits size), while DWC AHCI SATA
> controller can't be configured with more than 8 ports activated. So let's
> discard the SATA ports reg-property restrictions and just make sure that
> it consists of a single reg-item.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  Documentation/devicetree/bindings/ata/sata-common.yaml | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/ata/sata-common.yaml b/Documentation/devicetree/bindings/ata/sata-common.yaml
> index 7ac77b1c5850..c619f0ae72fb 100644
> --- a/Documentation/devicetree/bindings/ata/sata-common.yaml
> +++ b/Documentation/devicetree/bindings/ata/sata-common.yaml
> @@ -41,11 +41,10 @@ patternProperties:
>      properties:
>        reg:
>          minimum: 0
> -        maximum: 14

Why remove this ? Since AHCI can have up to 32 ports, then change the
value to 31. As the comment at the top of the file says, this is not
intended to be a device tree binding spec, but defines properties common
to most adapters.

>          description:
> -          The ID number of the drive port SATA can potentially use a port
> -          multiplier making it possible to connect up to 15 disks to a single
> -          SATA port.
> +          The ID number of the SATA port. Aside with being directly used
> +          each port can have a Port Multiplier attached thus allowing to
> +          access more than one drive by means of a single channel.

Please add a comma after "Aside with being directly used", otherwise the
sentence is hard to understand. And replace "channel" with "SATA port" to
stick with the terms defined here.

>  
>  additionalProperties: true
>  


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
  2022-03-24  0:58   ` Damien Le Moal
@ 2022-03-29  8:20   ` Damien Le Moal
  1 sibling, 0 replies; 65+ messages in thread
From: Damien Le Moal @ 2022-03-29  8:20 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede, Jens Axboe
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/24/22 09:16, Serge Semin wrote:
> It's better for readability and maintainability to explicitly assign an
> error number to the variable used then as a return value from the method
> on the cleanup-on-error path. So adding new code in the method we won't
> have to think whether the overridden rc-variable is set afterward in case
> of an error. Saving one line of code doesn't worth it especially seeing
> the rest of the ahci_platform_get_resources() function errors handling
> blocks do explicitly write errno to rc.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/libahci_platform.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 18296443ccba..1bd2f1686239 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  	struct ahci_host_priv *hpriv;
>  	struct clk *clk;
>  	struct device_node *child;
> -	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
> +	int i, enabled_ports = 0, rc = 0, child_nodes;

You I did say that I do not like this. Especially considering that this
function uses rc only in the case of an error return. Having it uselessly
initialized to 0 does not make sense and goes against your goal of
avoiding problems in case it is not set in an error path. returning
"ERR_PTR(0)" is the same as returning NULL, which defeats the purpose of
using ERR_PTR/PTR_ERR.

Please drop this patch.

>  	u32 mask_port_map = 0;
>  
>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> @@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  
>  	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
>  			     GFP_KERNEL);
> -	if (!hpriv)
> +	if (!hpriv) {
> +		rc = -ENOMEM;
>  		goto err_out;
> +	}
>  
>  	devres_add(dev, hpriv);
>  


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support
  2022-03-28 20:06 ` [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Damien Le Moal
@ 2022-03-29  8:30   ` Damien Le Moal
  2022-04-06 19:54     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-03-29  8:30 UTC (permalink / raw)
  To: Serge Semin, Hans de Goede
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Rob Herring,
	linux-ide, linux-kernel, devicetree

On 3/29/22 05:06, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> [...]
>> After the denoted above functionality is added we can finally introduce
>> the Baikal-T1 AHCI SATA controller support into the DWC AHCI SATA driver.
>> The controller is based on the DWC AHCI SATA IP-core v4.10a and can work
>> well with the generic DWC AHCI driver. The only peculiarity of it is
>> connected with the SATA Ports reference clock source. It can be supplied
>> either from the internal SoC PLL or from the chip pads. Currently we have
>> to prefer selecting the signal coming from the pads if the corresponding
>> clock source is specified because the link doesn't get stably established
>> when the internal clock signal is activated. In addition the platform has
>> trigger-based reset signals so the corresponding flag must be passed to
>> the generic AHCI-resource getter.
>>
> 
> I am assuming this is "v2" of your patches. Please add this version number
> to your patch titles ("[PATCH v2]") and add a changelog here in the cover
> letter.

Sorry. It looks like I received again the same patch series. Not sure why.
I assumed it was a V2, but it is not.

> 
>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
>> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
>> Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
>> Cc: Rob Herring <robh+dt@kernel.org>
>> Cc: linux-ide@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org
>> Cc: devicetree@vger.kernel.org
>>
>> Serge Semin (21):
>>   dt-bindings: ata: sata: Extend number of SATA ports
>>   dt-bindings: ata: Convert AHCI-bindings to DT schema
>>   ata: libahci_platform: Explicitly set rc on devres_alloc failure
>>   ata: libahci_platform: Convert to using handy devm-ioremap methods
>>   ata: libahci_platform: Convert to using devm bulk clocks API
>>   ata: libahci_platform: Add function returning a clock-handle by id
>>   ata: libahci_platform: Sanity check the DT child nodes number
>>   ata: libahci_platform: Parse ports-implemented property in resources
>>     getter
>>   ata: libahci_platform: Introduce reset assertion/deassertion methods
>>   dt-bindings: ata: ahci: Add platform capability properties
>>   ata: libahci: Extend port-cmd flags set with port capabilities
>>   ata: libahci: Discard redundant force_port_map parameter
>>   ata: libahci: Don't read AHCI version twice in the save-config method
>>   ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
>>   ata: ahci: Introduce firmware-specific caps initialization
>>   dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
>>   ata: ahci: Add DWC AHCI SATA controller support
>>   dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
>>   ata: ahci-dwc: Add platform-specific quirks support
>>   ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
>>   MAINTAINERS: Add maintainers for DWC AHCI SATA driver
>>
>>  .../devicetree/bindings/ata/ahci-common.yaml  | 176 ++++++
>>  .../devicetree/bindings/ata/ahci-platform.txt |  79 ---
>>  .../bindings/ata/baikal,bt1-ahci.yaml         | 132 +++++
>>  .../devicetree/bindings/ata/generic-ahci.yaml |  98 ++++
>>  .../devicetree/bindings/ata/sata-common.yaml  |   7 +-
>>  .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++
>>  MAINTAINERS                                   |   9 +
>>  drivers/ata/Kconfig                           |  11 +
>>  drivers/ata/Makefile                          |   1 +
>>  drivers/ata/ahci.c                            |   4 +-
>>  drivers/ata/ahci.h                            |  21 +-
>>  drivers/ata/ahci_dwc.c                        | 525 ++++++++++++++++++
>>  drivers/ata/ahci_mtk.c                        |   2 -
>>  drivers/ata/ahci_platform.c                   |   5 -
>>  drivers/ata/ahci_st.c                         |   3 -
>>  drivers/ata/libahci.c                         |  63 ++-
>>  drivers/ata/libahci_platform.c                | 234 +++++---
>>  include/linux/ahci_platform.h                 |   8 +-
>>  18 files changed, 1321 insertions(+), 178 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
>>  delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
>>  create mode 100644 Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
>>  create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml
>>  create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
>>  create mode 100644 drivers/ata/ahci_dwc.c
>>
> 
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
  2022-03-24  0:16 ` [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema Serge Semin
@ 2022-04-01  0:06   ` Rob Herring
  2022-04-11 20:00     ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Rob Herring @ 2022-04-01  0:06 UTC (permalink / raw)
  To: Serge Semin
  Cc: Damien Le Moal, Hans de Goede, Jens Axboe, Serge Semin,
	Alexey Malahov, Pavel Parkhomenko, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 03:16:23AM +0300, Serge Semin wrote:
> Synopsys AHCI SATA controller is mainly compatible with the generic AHCI
> SATA controller except a few peculiarities and the platform environment
> requirements. In particular it can have one or two reference clocks to
> feed up its AXI/AHB interface and SATA PHYs domain and at least one reset
> control for the application clock domain. In addition to that the DMA
> interface of each port can be tuned up to work with the predefined maximum
> data chunk size. Note unlike generic AHCI controller DWC AHCI can't have
> more than 8 ports. All of that is reflected in the new DWC AHCI SATA
> device DT binding.
> 
> Note the DWC AHCI SATA controller DT-schema has been created in a way so
> to be reused for the vendor-specific DT-schemas. One of which we are about
> to introduce.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++++++++++++++++
>  1 file changed, 121 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> 
> diff --git a/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> new file mode 100644
> index 000000000000..b443154b63aa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> @@ -0,0 +1,121 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/ata/snps,dwc-ahci.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DWC AHCI SATA controller
> +
> +maintainers:
> +  - Serge Semin <fancer.lancer@gmail.com>
> +
> +description: |
> +  This document defines device tree bindings for the Synopsys DWC
> +  implementation of the AHCI SATA controller.
> +
> +allOf:
> +  - $ref: ahci-common.yaml#
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - description: Synopsys AHCI SATA-compatible devices
> +        contains:
> +          const: snps,dwc-ahci
> +      - description: SPEAr1340 AHCI SATA device
> +        const: snps,spear-ahci
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    description:
> +      Basic DWC AHCI SATA clock sources like application AXI/AHB BIU clock
> +      and embedded PHYs reference clock together with vendor-specific set
> +      of clocks.
> +    minItems: 1
> +    maxItems: 4
> +
> +  clock-names:
> +    contains:
> +      anyOf:
> +        - description: Application AXI/AHB BIU clock source
> +          enum:
> +            - aclk
> +            - sata
> +        - description: SATA Ports reference clock
> +          enum:
> +            - ref
> +            - sata_ref
> +
> +  resets:
> +    description:
> +      At least basic core and application clock domains reset is normally
> +      supported by the DWC AHCI SATA controller. Some platform specific
> +      clocks can be also specified though.
> +
> +  reset-names:
> +    contains:
> +      description: Core and application clock domains reset control
> +      const: arst
> +
> +patternProperties:
> +  "^sata-port@[0-9a-e]$":
> +    type: object
> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 7
> +
> +      snps,tx-ts-max:
> +        $ref: /schemas/types.yaml#/definitions/uint32
> +        description: Maximal size of Tx DMA transactions in FIFO words
> +        minimum: 1
> +        maximum: 1024
> +
> +      snps,rx-ts-max:
> +        $ref: /schemas/types.yaml#/definitions/uint32
> +        description: Maximal size of Rx DMA transactions in FIFO words
> +        minimum: 1
> +        maximum: 1024

Are you reading these somewhere? 

Only powers of 2 are valid. (Guess what Calxeda's controller uses.)

Rob

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

* Re: [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support
  2022-03-29  8:30   ` Damien Le Moal
@ 2022-04-06 19:54     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-06 19:54 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Alexey Malahov, Pavel Parkhomenko,
	Rob Herring, linux-ide, linux-kernel, devicetree

Hello Damien

On Tue, Mar 29, 2022 at 05:30:43PM +0900, Damien Le Moal wrote:
> On 3/29/22 05:06, Damien Le Moal wrote:
> > On 3/24/22 09:16, Serge Semin wrote:
> > [...]
> >> After the denoted above functionality is added we can finally introduce
> >> the Baikal-T1 AHCI SATA controller support into the DWC AHCI SATA driver.
> >> The controller is based on the DWC AHCI SATA IP-core v4.10a and can work
> >> well with the generic DWC AHCI driver. The only peculiarity of it is
> >> connected with the SATA Ports reference clock source. It can be supplied
> >> either from the internal SoC PLL or from the chip pads. Currently we have
> >> to prefer selecting the signal coming from the pads if the corresponding
> >> clock source is specified because the link doesn't get stably established
> >> when the internal clock signal is activated. In addition the platform has
> >> trigger-based reset signals so the corresponding flag must be passed to
> >> the generic AHCI-resource getter.
> >>
> > 

> > I am assuming this is "v2" of your patches. Please add this version number
> > to your patch titles ("[PATCH v2]") and add a changelog here in the cover
> > letter.
> 
> Sorry. It looks like I received again the same patch series. Not sure why.
> I assumed it was a V2, but it is not.

Most likely you've received the series released by the mailing list
service.  I've sent four patchsets at a time then, and I guess the
spam-filter was unhappy about that. So all the series were sustained
for some time and were unavailable in the lore and patchwork. In after
about four days they turned to be finally available. At least I
finally was able to see my patchsets there after getting your messages
above, which made me to re-check the series status.

-Sergey

> 
> > 
> >> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> >> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> >> Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
> >> Cc: Rob Herring <robh+dt@kernel.org>
> >> Cc: linux-ide@vger.kernel.org
> >> Cc: linux-kernel@vger.kernel.org
> >> Cc: devicetree@vger.kernel.org
> >>
> >> Serge Semin (21):
> >>   dt-bindings: ata: sata: Extend number of SATA ports
> >>   dt-bindings: ata: Convert AHCI-bindings to DT schema
> >>   ata: libahci_platform: Explicitly set rc on devres_alloc failure
> >>   ata: libahci_platform: Convert to using handy devm-ioremap methods
> >>   ata: libahci_platform: Convert to using devm bulk clocks API
> >>   ata: libahci_platform: Add function returning a clock-handle by id
> >>   ata: libahci_platform: Sanity check the DT child nodes number
> >>   ata: libahci_platform: Parse ports-implemented property in resources
> >>     getter
> >>   ata: libahci_platform: Introduce reset assertion/deassertion methods
> >>   dt-bindings: ata: ahci: Add platform capability properties
> >>   ata: libahci: Extend port-cmd flags set with port capabilities
> >>   ata: libahci: Discard redundant force_port_map parameter
> >>   ata: libahci: Don't read AHCI version twice in the save-config method
> >>   ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
> >>   ata: ahci: Introduce firmware-specific caps initialization
> >>   dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
> >>   ata: ahci: Add DWC AHCI SATA controller support
> >>   dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
> >>   ata: ahci-dwc: Add platform-specific quirks support
> >>   ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
> >>   MAINTAINERS: Add maintainers for DWC AHCI SATA driver
> >>
> >>  .../devicetree/bindings/ata/ahci-common.yaml  | 176 ++++++
> >>  .../devicetree/bindings/ata/ahci-platform.txt |  79 ---
> >>  .../bindings/ata/baikal,bt1-ahci.yaml         | 132 +++++
> >>  .../devicetree/bindings/ata/generic-ahci.yaml |  98 ++++
> >>  .../devicetree/bindings/ata/sata-common.yaml  |   7 +-
> >>  .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++
> >>  MAINTAINERS                                   |   9 +
> >>  drivers/ata/Kconfig                           |  11 +
> >>  drivers/ata/Makefile                          |   1 +
> >>  drivers/ata/ahci.c                            |   4 +-
> >>  drivers/ata/ahci.h                            |  21 +-
> >>  drivers/ata/ahci_dwc.c                        | 525 ++++++++++++++++++
> >>  drivers/ata/ahci_mtk.c                        |   2 -
> >>  drivers/ata/ahci_platform.c                   |   5 -
> >>  drivers/ata/ahci_st.c                         |   3 -
> >>  drivers/ata/libahci.c                         |  63 ++-
> >>  drivers/ata/libahci_platform.c                | 234 +++++---
> >>  include/linux/ahci_platform.h                 |   8 +-
> >>  18 files changed, 1321 insertions(+), 178 deletions(-)
> >>  create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
> >>  delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
> >>  create mode 100644 Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
> >>  create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml
> >>  create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> >>  create mode 100644 drivers/ata/ahci_dwc.c
> >>
> > 
> > 
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure
  2022-03-25  1:56       ` Damien Le Moal
@ 2022-04-06 20:03         ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-06 20:03 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Fri, Mar 25, 2022 at 10:56:29AM +0900, Damien Le Moal wrote:
> On 2022/03/25 6:37, Serge Semin wrote:
> > Hello Damien
> > 
> > On Thu, Mar 24, 2022 at 09:58:34AM +0900, Damien Le Moal wrote:
> >> On 3/24/22 09:16, Serge Semin wrote:
> >>> It's better for readability and maintainability to explicitly assign an
> >>> error number to the variable used then as a return value from the method
> >>> on the cleanup-on-error path. So adding new code in the method we won't
> >>
> > 
> >> No it is not. On-stack variable initialization is not free. So if
> >> initializing the variable is not needed, do not do it.
> > 
> > This patch isn't about on-stack initialization, but about bringing an
> > order to the error-handling procedure of the
> > ahci_platform_get_resources() method. Explicitly setting the rc variable
> > with an error value closer to the place caused the error much easier
> > to perceive than keeping in mind that the variable has been set with
> > some default value. That turns to be even more justified seeing the
> > rest of the method does it that way.
> 
> I agree with that change. Setting "rc = -ENOMEM" under the "if" checking for
> error is fine.
> 
> > 
> > See my next comment regarding the initialization.
> > 
> >>
> >>> have to think whether the overridden rc-variable is set afterward in case
> >>> of an error. Saving one line of code doesn't worth it especially seeing
> >>> the rest of the ahci_platform_get_resources() function errors handling
> >>> blocks do explicitly write errno to rc.
> >>>
> >>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> >>> ---
> >>>  drivers/ata/libahci_platform.c | 6 ++++--
> >>>  1 file changed, 4 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> >>> index 18296443ccba..1bd2f1686239 100644
> >>> --- a/drivers/ata/libahci_platform.c
> >>> +++ b/drivers/ata/libahci_platform.c
> >>> @@ -389,7 +389,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >>>  	struct ahci_host_priv *hpriv;
> >>>  	struct clk *clk;
> >>>  	struct device_node *child;
> >>> -	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
> >>> +	int i, enabled_ports = 0, rc = 0, child_nodes;
> >>>  	u32 mask_port_map = 0;
> >>>  
> >>>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> >>> @@ -397,8 +397,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >>>  
> >>>  	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
> >>>  			     GFP_KERNEL);
> >>> -	if (!hpriv)
> >>> +	if (!hpriv) {
> >>> +		rc = -ENOMEM;
> >>>  		goto err_out;
> >>> +	}
> >>
> > 
> >> If you set rc to -ENOMEM here, then the 0 initialization of rc is not needed.
> > 
> > Normally you are right. But the case of the rc/ret/etc variables is
> > special. I'd stick with having it defaulted to 0 here. Here is why.
> > 
> > When it comes to using the rc/ret/etc variables the maintainability
> > gets to be more important than some small optimization (especially
> > here seeing the ahci_platform_get_resources() is called once per
> > device life-time) because in case of the method alteration these
> > variables very often get to be involved in one way or another. If due
> > to a mistake the rc/ret/etc variable isn't updated in case of an
> > erroneous situation but the method is terminated with the goto-pattern
> > and rc/ret/etc isn't initialized with any default value then we will
> > end up with having a garbage pointer returned. We'd be lucky if it was
> > a null pointer, but in general it can be a reference to some random
> > memory region. In the later case the kernel may experience random
> > crashes with hard-to-find cause of the problem. In the former case the
> > problem would have been tracked right away on the testing stage by
> > getting the system invalid-pointer de-reference crash. That's why
> > defaulting the variable to zero here is still useful.
> 

> No it is not. We have code reviews and testing to catch mistakes. If we start
> thinking along these lines, any useless local variable initialization can be
> justified. So let's not go there please.

Ok. That's up to the maintainer to decide after all. I'll just drop the
initialization as you say then.

-Sergey

> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods
  2022-03-24  1:11   ` Damien Le Moal
@ 2022-04-06 20:42     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-06 20:42 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 10:11:09AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Currently the IOMEM AHCI registers space is mapped by means of the
> > two functions invocation: platform_get_resource() is used to get the very
> > first memory resource and devm_ioremap_resource() is called to remap that
> > resource. Device-managed kernel API provides a handy wrapper to perform
> > the same in single function call: devm_platform_ioremap_resource().
> 
> > 
> > While at it seeing many AHCI platform drivers rely on having the AHCI CSR
> > space marked with "ahci" name let's first try to find and remap the CSR
> > IO-mem with that name and only if it fails fallback to getting the very
> > first registers space platform resource.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/libahci_platform.c | 10 ++++++----
> >  1 file changed, 6 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index 1bd2f1686239..8eabbb5f208c 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -404,11 +404,13 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  
> >  	devres_add(dev, hpriv);
> >  
> > -	hpriv->mmio = devm_ioremap_resource(dev,
> > -			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
> > +	hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");
> 

> See __devm_ioremap_resource(): if there is no resource named "ahci" found,
> then this will print an error message ("invalid resource\n"). That may
> confuse users as this error message was not present before. So you may
> want to change this code to something like this:

Right. I should have checked that the method can print an error
message in the log. Thanks for the heads-up. I'll fix the patch as you
suggest. It's a pity there is no an alternative with "_optional"
semantics though.

-Sergey

> 
> /*
>  * If the DT provided an "ahci" named resource, use it. Otherwise,
>  * fallback to using the default first resource for the device node.
>  */
> if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"))
> 	hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");
> else
> 	hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(hpriv->mmio)) {
> 	rc = PTR_ERR(hpriv->mmio);
> 	goto err_out;
> }
> 
> >  	if (IS_ERR(hpriv->mmio)) {
> > -		rc = PTR_ERR(hpriv->mmio);
> > -		goto err_out;
> > +		hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
> > +		if (IS_ERR(hpriv->mmio)) {
> > +			rc = PTR_ERR(hpriv->mmio);
> > +			goto err_out;
> > +		}
> >  	}
> >  
> >  	for (i = 0; i < AHCI_MAX_CLKS; i++) {
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
  2022-03-24  1:29   ` Damien Le Moal
@ 2022-04-09  4:59     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-09  4:59 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 10:29:01AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > In order to simplify the clock-related code there is a way to convert the
> > current fixed clocks array into using the common bulk clocks kernel API
> > with dynamic set of the clock handlers and device-managed clock-resource
> > tracking. It's a bit tricky due to the complication coming from the
> > requirement to support the platforms (da850, spear13xx) with the
> > non-OF-based clock source, but still doable.
> > 
> > Before this modification there are two methods have been used to get the
> > clocks connected to an AHCI device: clk_get() - to get the very first
> > clock in the list and of_clk_get() - to get the rest of them. Basically
> > the platforms with non-OF-based clocks definition could specify only a
> > single reference clock source. The platforms with OF-hw clocks have been
> > luckier and could setup up to AHCI_MAX_CLKS clocks. Such semantic can be
> > retained with using devm_clk_bulk_get_all() to retrieve the clocks defined
> > via the DT firmware and devm_clk_get_optional() otherwise. In both cases
> > using the device-managed version of the methods will cause the automatic
> > resources deallocation on the AHCI device removal event. The only
> > complicated part in the suggested approach is the explicit allocation and
> > initialization of the clk_bulk_data structure instance for the non-OF
> > reference clocks. It's required in order to use the Bulk Clocks API for
> > the both denoted cases of the clocks definition.
> > 
> > Note aside with the clock-related code reduction and natural
> > simplification, there are several bonuses the suggested modification
> > provides. First of all the limitation of having no greater than
> > AHCI_MAX_CLKS clocks is now removed, since the devm_clk_bulk_get_all()
> > method will allocate as many reference clocks data descriptors as there
> > are clocks specified for the device. Secondly the clock names are
> > auto-detected. So the glue drivers can make sure that the required clocks
> > are specified just by checking the clock IDs in the clk_bulk_data array.
> > Thirdly using the handy Bulk Clocks kernel API improves the
> > clocks-handling code readability. And the last but not least this
> > modification implements a true optional clocks support to the
> > ahci_platform_get_resources() method. Indeed the previous clocks getting
> > procedure just stopped getting the clocks on any errors (aside from
> > non-critical -EPROBE_DEFER) in a way so the callee wasn't even informed
> > about abnormal loop termination. The new implementation lacks of such
> > problem. The ahci_platform_get_resources() will return an error code if
> > the corresponding clocks getting method ends execution abnormally.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/ahci.h             |  4 +-
> >  drivers/ata/libahci_platform.c | 82 +++++++++++++++-------------------
> >  2 files changed, 37 insertions(+), 49 deletions(-)
> > 
> > diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> > index eeac5482f1d1..1564c691094a 100644
> > --- a/drivers/ata/ahci.h
> > +++ b/drivers/ata/ahci.h
> > @@ -38,7 +38,6 @@
> >  
> >  enum {
> >  	AHCI_MAX_PORTS		= 32,
> > -	AHCI_MAX_CLKS		= 5,
> >  	AHCI_MAX_SG		= 168, /* hardware max is 64K */
> >  	AHCI_DMA_BOUNDARY	= 0xffffffff,
> >  	AHCI_MAX_CMDS		= 32,
> > @@ -341,7 +340,8 @@ struct ahci_host_priv {
> >  	u32			em_msg_type;	/* EM message type */
> >  	u32			remapped_nvme;	/* NVMe remapped device count */
> >  	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
> > -	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
> > +	unsigned int		n_clks;
> > +	struct clk_bulk_data	*clks;		/* Optional */
> >  	struct reset_control	*rsts;		/* Optional */
> >  	struct regulator	**target_pwrs;	/* Optional */
> >  	struct regulator	*ahci_regulator;/* Optional */
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index 8eabbb5f208c..d805ddc3a024 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -8,6 +8,7 @@
> >   *   Anton Vorontsov <avorontsov@ru.mvista.com>
> >   */
> >  
> > +#include <linux/clk-provider.h>
> >  #include <linux/clk.h>
> >  #include <linux/kernel.h>
> >  #include <linux/gfp.h>
> > @@ -97,28 +98,14 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
> >   * ahci_platform_enable_clks - Enable platform clocks
> >   * @hpriv: host private area to store config values
> >   *
> > - * This function enables all the clks found in hpriv->clks, starting at
> > - * index 0. If any clk fails to enable it disables all the clks already
> > - * enabled in reverse order, and then returns an error.
> > + * This function enables all the clks found for the AHCI device.
> >   *
> >   * RETURNS:
> >   * 0 on success otherwise a negative error code
> >   */
> >  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
> >  {
> > -	int c, rc;
> > -
> > -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
> > -		rc = clk_prepare_enable(hpriv->clks[c]);
> > -		if (rc)
> > -			goto disable_unprepare_clk;
> > -	}
> > -	return 0;
> > -
> > -disable_unprepare_clk:
> > -	while (--c >= 0)
> > -		clk_disable_unprepare(hpriv->clks[c]);
> > -	return rc;
> > +	return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
> >  }
> >  EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
> >  
> > @@ -126,16 +113,13 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
> >   * ahci_platform_disable_clks - Disable platform clocks
> >   * @hpriv: host private area to store config values
> >   *
> > - * This function disables all the clks found in hpriv->clks, in reverse
> > - * order of ahci_platform_enable_clks (starting at the end of the array).
> > + * This function disables all the clocks enabled before
> > + * (bulk-clocks-disable function is supposed to do that in reverse
> > + * from the enabling procedure order).
> >   */
> >  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
> >  {
> > -	int c;
> > -
> > -	for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
> > -		if (hpriv->clks[c])
> > -			clk_disable_unprepare(hpriv->clks[c]);
> > +	clk_bulk_disable_unprepare(hpriv->n_clks, hpriv->clks);
> >  }
> >  EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
> >  
> > @@ -292,8 +276,6 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
> >  		pm_runtime_disable(dev);
> >  	}
> >  
> > -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
> > -		clk_put(hpriv->clks[c]);
> >  	/*
> >  	 * The regulators are tied to child node device and not to the
> >  	 * SATA device itself. So we can't use devm for automatically
> > @@ -374,8 +356,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
> >   * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
> >   * 2) regulator for controlling the targets power (optional)
> >   *    regulator for controlling the AHCI controller (optional)
> > - * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
> > - *    or for non devicetree enabled platforms a single clock
> > + * 3) all clocks specified in the devicetree node, or a single
> > + *    clock for non-OF platforms (optional)
> >   * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
> >   * 5) phys (optional)
> >   *
> > @@ -385,11 +367,10 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
> >  struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  						   unsigned int flags)
> >  {
> > +	int enabled_ports = 0, rc = 0, child_nodes;
> >  	struct device *dev = &pdev->dev;
> >  	struct ahci_host_priv *hpriv;
> > -	struct clk *clk;
> >  	struct device_node *child;
> > -	int i, enabled_ports = 0, rc = 0, child_nodes;
> >  	u32 mask_port_map = 0;
> >  
> >  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> > @@ -413,25 +394,32 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  		}
> >  	}
> >  
> > -	for (i = 0; i < AHCI_MAX_CLKS; i++) {
> > -		/*
> > -		 * For now we must use clk_get(dev, NULL) for the first clock,
> > -		 * because some platforms (da850, spear13xx) are not yet
> > -		 * converted to use devicetree for clocks.  For new platforms
> > -		 * this is equivalent to of_clk_get(dev->of_node, 0).
> > -		 */
> > -		if (i == 0)
> > -			clk = clk_get(dev, NULL);
> > -		else
> > -			clk = of_clk_get(dev->of_node, i);
> > -
> > -		if (IS_ERR(clk)) {
> > -			rc = PTR_ERR(clk);
> > -			if (rc == -EPROBE_DEFER)
> > -				goto err_out;
> > -			break;
> > +	/*
> > +	 * Bulk clock get procedure can fail to find any clock due to running
> > +	 * an a non-OF platform or due to the clocks being defined in bypass
> > +	 * from the DT firmware (like da850, spear13xx). In that case we
> > +	 * fallback to getting a single clock source right from the dev clocks
> > +	 * list.
> > +	 */
> > +	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
> 

> I would move the error check first here to make things more readable:

Agreed. Good note.

> 
> 	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
> 	if (rc < 0)
> 		goto err_out;
> 
> 	if (rc) {
> 		/* Got clocks in bulk */
> 		hpriv->n_clks = rc;
> 	} else {
> 		/*
> 		 * No clock bulk found: fallback to manually getting
> 		 * the optional clock.
> 		 */
> 		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks),
> 					   GFP_KERNEL);
> 		...
> 	}
> 
> And it may be cleaner to move this entire code hunk into a helper,
> something like ahci_platform_get_clks() ?

I'd rather keep the code embedded seeing it won't be used anywhere
than here and in order to keep the ahci_platform_get_resources()
function more-or-less coherent.  Otherwise moving just a part of the
function would be a half-measure since the methods like
ahci_platform_get_regs(), ahci_platform_get_regulators(), etc could be
also unpinned.

-Sergey

> 
> > +	if (rc > 0) {
> > +		hpriv->n_clks = rc;
> > +	} else if (!rc) {
> > +		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks), GFP_KERNEL);
> > +		if (!hpriv->clks) {
> > +			rc = -ENOMEM;
> > +			goto err_out;
> >  		}
> > -		hpriv->clks[i] = clk;
> > +		hpriv->clks->clk = devm_clk_get_optional(dev, NULL);
> > +		if (IS_ERR(hpriv->clks->clk)) {
> > +			rc = PTR_ERR(hpriv->clks->clk);
> > +			goto err_out;
> > +		} else if (hpriv->clks->clk) {
> > +			hpriv->clks->id = __clk_get_name(hpriv->clks->clk);
> > +			hpriv->n_clks = 1;
> > +		}
> > +	} else {
> > +		goto err_out;
> >  	}
> >  
> >  	hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id
  2022-03-24  1:36   ` Damien Le Moal
@ 2022-04-11  6:02     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11  6:02 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 10:36:04AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Since all the clocks are retrieved by the method
> > ahci_platform_get_resources() there is no need for the glue-drivers to be
> > looking for some particular of them in the kernel clocks table again.
> > Instead we suggest to add a simple method returning a device-specific
> > clock with passed connection ID if it is managed to be found. Otherwise
> > the function will return NULL. Thus the glue-drivers won't need to either
> 

> "glue-drivers" is really unclear. What do you mean ?

"Glue drivers" is a common name to address the drivers which are used to
pre-initialize the platform-specifics, then normally create a core driver
descriptor/data and finally call some core method (like
ahci_platform_init_host()) to really bind the device in the particular
bus. You can find them in almost all the kernel subsystems. For instance
in case of this patchset the glue-driver is drivers/ata/ahci_dwc.c, while
the main/core part of the driver is implemented in drivers/ata/achi.c,
drivers/ata/libahci.c, drivers/ata/libahci_platform.c, etc.

It's not like I've come up with the term by myself. I've seen it used in a
plenty of the kernel patches and subsystems and will unlikely stop using
it since it determines the particular type of the kernel drivers in a
short and direct manner.

> 
> > manually touching the hpriv->clks array or calling clk_get()-friends. The
> > AHCI platform drivers will be able to use the new function right after the
> > ahci_platform_get_resources() method invocation and up to the device
> > removal.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/libahci_platform.c | 27 +++++++++++++++++++++++++++
> >  include/linux/ahci_platform.h  |  3 +++
> >  2 files changed, 30 insertions(+)
> > 
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index d805ddc3a024..4fb9629c03ab 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -94,6 +94,33 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
> >  }
> >  EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
> >  
> > +/**
> > + * ahci_platform_find_clk - Find platform clock
> > + * @hpriv: host private area to store config values
> > + * @con_id: clock connection ID
> > + *
> > + * This function returns point to the clock descriptor of the clock with
> > + * passed ID.
> > + *
> > + * RETURNS:
> > + * Pointer to the clock descriptor on success otherwise NULL
> > + */
> > +struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id)
> > +{
> > +	struct clk *clk = NULL;
> > +	int i;
> > +
> > +	for (i = 0; i < hpriv->n_clks; i++) {
> > +		if (!strcmp(hpriv->clks[i].id, con_id)) {
> > +			clk = hpriv->clks[i].clk;
> > +			break;
> > +		}
> > +	}
> > +
> > +	return clk;
> > +}
> > +EXPORT_SYMBOL_GPL(ahci_platform_find_clk);
> > +
> >  /**
> >   * ahci_platform_enable_clks - Enable platform clocks
> >   * @hpriv: host private area to store config values
> > diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
> > index 49e5383d4222..fd964e6a68d6 100644
> > --- a/include/linux/ahci_platform.h
> > +++ b/include/linux/ahci_platform.h
> > @@ -13,6 +13,7 @@
> >  
> >  #include <linux/compiler.h>
> >  
> > +struct clk;
> >  struct device;
> >  struct ata_port_info;
> >  struct ahci_host_priv;
> > @@ -21,6 +22,8 @@ struct scsi_host_template;
> >  
> >  int ahci_platform_enable_phys(struct ahci_host_priv *hpriv);
> >  void ahci_platform_disable_phys(struct ahci_host_priv *hpriv);
> > +struct clk *
> > +ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);
> 

> No users for this function ?

It will be used in the next two patches:
[PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
[PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
and most likely in the new AHCI/SATA drivers which need to tune the clocks
up in the platform-specific way.

-Sergey

> 
> >  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
> >  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
> >  int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods
  2022-03-24  1:52   ` Damien Le Moal
@ 2022-04-11 10:57     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 10:57 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 10:52:27AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Currently the ACHI-platform library supports only the assert and deassert
> > reset signals and ignores the platforms with self-deasserting reset lines.
> > That prone to having the platforms with self-deasserting reset method
> > misbehaviour when it comes to resuming from sleep state after the clocks
> > have been fully disabled. For such cases the controller needs to be fully
> > reset all over after the reference clocks are enabled and stable,
> > otherwise the controller state machine might be in an undetermined state.
> > 
> > The best solution would be to auto-detect which reset method is supported
> > by the particular platform and use it implicitly in the framework of the
> > ahci_platform_enable_resources()/ahci_platform_disable_resources()
> > methods. Alas it can't be implemented due to the AHCI-platform library
> > already supporting the shared reset control lines. As [1] says in such
> > case we have to use only one of the next methods:
> > + reset_control_assert()/reset_control_deassert();
> > + reset_control_reset()/reset_control_rearm().
> > If the driver had an exclusive control over the reset lines we could have
> > been able to manipulate the lines with no much limitation and just used
> > the combination of the methods above to cover all the possible
> > reset-control cases. Since the shared reset control has already been
> > advertised and couldn't be changed with no risk to breaking the platforms
> > relying on it, we have no choice but to make the platform drivers to
> > determine which reset methods the platform reset system supports.
> > 
> > In order to implement both types of reset control support we suggest to
> > introduce the new AHCI-platform flag: AHCI_PLATFORM_RST_TRIGGER, which
> > when passed to the ahci_platform_get_resources() method together with the
> > AHCI_PLATFORM_GET_RESETS flag will indicate that the reset lines are
> > self-deasserting thus the reset_control_reset()/reset_control_rearm() will
> > be used to control the reset state. Otherwise the
> > reset_control_deassert()/reset_control_assert() methods will be utilized.
> > 
> > [1] Documentation/driver-api/reset.rst
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/ahci.h             |  1 +
> >  drivers/ata/libahci_platform.c | 47 ++++++++++++++++++++++++++++++----
> >  include/linux/ahci_platform.h  |  5 +++-
> >  3 files changed, 47 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> > index 1564c691094a..0b1d5c24cb8c 100644
> > --- a/drivers/ata/ahci.h
> > +++ b/drivers/ata/ahci.h
> > @@ -342,6 +342,7 @@ struct ahci_host_priv {
> >  	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
> >  	unsigned int		n_clks;
> >  	struct clk_bulk_data	*clks;		/* Optional */
> > +	unsigned int		f_rsts;
> 

> Why ? using flags directly is not OK ?

First of all I didn't want to mix up the AHCI and platform-specific
flags especially seeing there aren't that many free bits left in the
hpriv->flags field. Secondly a new platform-specific flags set has
already been defined in commit 9d2ab9957397 ("ata: libahci_platform:
add reset control support"). Thus mixing up AHCI_HFLAG* and
AHCI_PLATFORM* flags in a single field wouldn't have been that
maintainable. So to speak at least for v1 I decided to add a new
reset-specific field to preserve the reset-related flags only. It
might have been more reasonable to create a generic storage like
p_flags for all platform-specific flags. But it's up to you to decide
after all. What do you think?

> 
> >  	struct reset_control	*rsts;		/* Optional */
> >  	struct regulator	**target_pwrs;	/* Optional */
> >  	struct regulator	*ahci_regulator;/* Optional */
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index 5998e735a813..febad33aa43c 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -150,6 +150,41 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
> >  }
> >  EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
> >  
> > +/**
> > + * ahci_platform_deassert_rsts - Deassert/trigger platform resets
> > + * @hpriv: host private area to store config values
> > + *
> > + * This function desserts or triggers all the reset lanes found for the AHCI
> 

> s/desserts/deasserts ?
> s/lanes/lines ?

Ok.

> 
> > + * device.
> > + *
> > + * RETURNS:
> > + * 0 on success otherwise a negative error code
> > + */
> > +int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv)
> > +{
> > +	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
> > +		return reset_control_reset(hpriv->rsts);
> > +
> > +	return reset_control_deassert(hpriv->rsts);
> > +}
> > +EXPORT_SYMBOL_GPL(ahci_platform_deassert_rsts);
> > +
> > +/**
> > + * ahci_platform_assert_rsts - Assert/rearm platform resets
> > + * @hpriv: host private area to store config values
> > + *
> > + * This function asserts or rearms (for self-deasserting resets) all the reset
> > + * controls found for the AHCI device.
> > + */
> > +void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv)
> > +{
> > +	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
> > +		return (void)reset_control_rearm(hpriv->rsts);
> 

> return void in a void function ? How does this even compile ?

Well, apparently it does.) I was also surprised not to have any
warning printed from the compiler. Most likely the silent 
behavior was caused by the explicit cast to void. 

Regarding my reasoning. In this case using the return operator that
way spared the two lines of code and let not to use the 'else'
operator. If I didn't use the return operator like that I would have
needed to implement the statements like this:
+	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER) {
+		(void)reset_control_rearm(hpriv->rsts);
+		return;
+	}
+
+	reset_control_assert(hpriv->rsts);
or like this:
+	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
+		(void)reset_control_rearm(hpriv->rsts);
+	else
+		reset_control_assert(hpriv->rsts);

I've decided to try a more simple pattern. If you think it's too
questionable and shouldn't be used I'll drop the return operator.
Do you want me to?

> And what if reset_control_rearm() fails ? What happens ?

Happens the same as before this commit in case of the
reset_control_assert() method invocation failure. The error will be just
ignored. As you can see the ahci_platform_assert_rsts() method is only
utilized in the resources disable procedure or in the revert-on-error
path of the ahci_platform_enable_resources() function. The driver
doesn't check the return values in none of these places.

I still think that we shouldn't convert the code to checking the
status in these parts, but I can add the return status to the
ahci_platform_assert_rsts() method like this:
+int ahci_platform_assert_rsts(struct ahci_host_priv *hpriv)
+{
+	if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
+		return reset_control_rearm(hpriv->rsts);
+
+	return reset_control_assert(hpriv->rsts);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts);

How do you feel about this?

-Sergey

> 
> > +
> > +	reset_control_assert(hpriv->rsts);
> > +}
> > +EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts);
> > +
> >  /**
> >   * ahci_platform_enable_regulators - Enable regulators
> >   * @hpriv: host private area to store config values
> > @@ -247,18 +282,18 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
> >  	if (rc)
> >  		goto disable_regulator;
> >  
> > -	rc = reset_control_deassert(hpriv->rsts);
> > +	rc = ahci_platform_deassert_rsts(hpriv);
> >  	if (rc)
> >  		goto disable_clks;
> >  
> >  	rc = ahci_platform_enable_phys(hpriv);
> >  	if (rc)
> > -		goto disable_resets;
> > +		goto disable_rsts;
> >  
> >  	return 0;
> >  
> > -disable_resets:
> > -	reset_control_assert(hpriv->rsts);
> > +disable_rsts:
> > +	ahci_platform_assert_rsts(hpriv);
> >  
> >  disable_clks:
> >  	ahci_platform_disable_clks(hpriv);
> > @@ -285,7 +320,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
> >  {
> >  	ahci_platform_disable_phys(hpriv);
> >  
> > -	reset_control_assert(hpriv->rsts);
> > +	ahci_platform_assert_rsts(hpriv);
> >  
> >  	ahci_platform_disable_clks(hpriv);
> >  
> > @@ -468,6 +503,8 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  			rc = PTR_ERR(hpriv->rsts);
> >  			goto err_out;
> >  		}
> > +
> > +		hpriv->f_rsts = flags & AHCI_PLATFORM_RST_TRIGGER;
> 

> Why not use hpriv->flags ?

Please see my first comment.

-Sergey

> 
> >  	}
> >  
> >  	/*
> > diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
> > index fd964e6a68d6..57d25d30a9fa 100644
> > --- a/include/linux/ahci_platform.h
> > +++ b/include/linux/ahci_platform.h
> > @@ -26,6 +26,8 @@ struct clk *
> >  ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id);
> >  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
> >  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
> > +int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv);
> > +void ahci_platform_assert_rsts(struct ahci_host_priv *hpriv);
> >  int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
> >  void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
> >  int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
> > @@ -44,6 +46,7 @@ int ahci_platform_resume_host(struct device *dev);
> >  int ahci_platform_suspend(struct device *dev);
> >  int ahci_platform_resume(struct device *dev);
> >  
> > -#define AHCI_PLATFORM_GET_RESETS	0x01
> > +#define AHCI_PLATFORM_GET_RESETS	BIT(0)
> > +#define AHCI_PLATFORM_RST_TRIGGER	BIT(1)
> >  
> >  #endif /* _AHCI_PLATFORM_H */
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-03-24  2:05   ` Damien Le Moal
@ 2022-04-11 12:11     ` Serge Semin
  2022-04-11 12:25       ` Damien Le Moal
  0 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-04-11 12:11 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 11:05:58AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Currently there are four port-map-related fields declared in the
> > ahci_host_priv structure and used to setup the HBA ports mapping. First
> > the ports-mapping is read from the PI register and immediately stored in
> > the saved_port_map field. If forced_port_map is initialized with non-zero
> > value then its value will have greater priority over the value read from
> > PI, thus it will override the saved_port_map field. That value will be then
> > masked by a non-zero mask_port_map field and after some sanity checks it
> > will be stored in the ahci_host_priv.port_map field as a final port
> > mapping.
> > 
> > As you can see the logic is a bit too complicated for such a simple task.
> > We can freely get rid from at least one of the fields with no change to
> > the implemented semantic. The force_port_map field can be replaced with
> > taking non-zero saved_port_map value into account. So if saved_port_map is
> > pre-initialized by the glue-driver/platform-specific code then it will
> 

> glue-driver == LLDD (low level device driver), for the entire series please.

Why? It's a normal term and well known amongst developers. I've used it
in a plenty of my patches before and none of them has been questioned in that
part so far.

-Sergey

> 
> > have greater priority over the value read from PI register and will be
> > used as actual HBA ports mapping later on. Thus the ports map forcing task
> > will be just transferred from the force_port_map to saved_port_map field.
> > 
> > This modification will perfectly fit into the feature of having OF-based
> > initialization of the HW-init HBA CSR fields we are about to introduce in
> > the next commit.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/ata/ahci.c             |  2 +-
> >  drivers/ata/ahci.h             |  1 -
> >  drivers/ata/libahci.c          | 10 ++++++----
> >  drivers/ata/libahci_platform.c |  2 +-
> >  4 files changed, 8 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
> > index ab5811ef5a53..8ce0d166cc8d 100644
> > --- a/drivers/ata/ahci.c
> > +++ b/drivers/ata/ahci.c
> > @@ -654,7 +654,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
> >  {
> >  	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
> >  		dev_info(&pdev->dev, "JMB361 has only one port\n");
> > -		hpriv->force_port_map = 1;
> > +		hpriv->saved_port_map = 1;
> >  	}
> >  
> >  	/*
> > diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> > index 04690b4168a3..519d148ecaea 100644
> > --- a/drivers/ata/ahci.h
> > +++ b/drivers/ata/ahci.h
> > @@ -329,7 +329,6 @@ struct ahci_port_priv {
> >  struct ahci_host_priv {
> >  	/* Input fields */
> >  	unsigned int		flags;		/* AHCI_HFLAG_* */
> > -	u32			force_port_map;	/* force port map */
> >  	u32			mask_port_map;	/* mask out particular bits */
> >  
> >  	void __iomem *		mmio;		/* bus-independent mem map */
> > diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
> > index 0ed484e04fd6..011175e82174 100644
> > --- a/drivers/ata/libahci.c
> > +++ b/drivers/ata/libahci.c
> > @@ -453,7 +453,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
> >  	 * reset.  Values without are used for driver operation.
> >  	 */
> >  	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
> > -	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
> >  
> >  	/* CAP2 register is only defined for AHCI 1.2 and later */
> >  	vers = readl(mmio + HOST_VERSION);
> > @@ -517,10 +516,13 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
> >  		cap &= ~HOST_CAP_SXS;
> >  	}
> >  
> > -	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
> > +	/* Override the HBA ports mapping if the platform needs it */
> > +	port_map = readl(mmio + HOST_PORTS_IMPL);
> > +	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
> >  		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
> > -			 port_map, hpriv->force_port_map);
> > -		port_map = hpriv->force_port_map;
> > +			 port_map, hpriv->saved_port_map);
> > +		port_map = hpriv->saved_port_map;
> > +	} else {
> >  		hpriv->saved_port_map = port_map;
> >  	}
> >  
> > diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> > index febad33aa43c..5cbc2c42164d 100644
> > --- a/drivers/ata/libahci_platform.c
> > +++ b/drivers/ata/libahci_platform.c
> > @@ -539,7 +539,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >  	}
> >  
> >  	of_property_read_u32(dev->of_node,
> > -			     "ports-implemented", &hpriv->force_port_map);
> > +			     "ports-implemented", &hpriv->saved_port_map);
> >  
> >  	if (child_nodes) {
> >  		for_each_child_of_node(dev->of_node, child) {
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver
  2022-03-24  2:17   ` Damien Le Moal
@ 2022-04-11 12:16     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 12:16 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 11:17:12AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Add myself as a maintainer of the new DWC AHCI SATA driver and
> > its DT-bindings schema.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  MAINTAINERS | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index cd0f68d4a34a..19c9ea0758cc 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -10919,6 +10919,15 @@ F:	drivers/ata/ahci_platform.c
> >  F:	drivers/ata/libahci_platform.c
> >  F:	include/linux/ahci_platform.h
> >  
> > +LIBATA SATA AHCI SYNOPSYS DWC CONTROLLER DRIVER
> > +M:	Serge Semin <fancer.lancer@gmail.com>
> > +L:	linux-ide@vger.kernel.org
> > +S:	Maintained
> > +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
> 

> Wrong tree. This should be libata tree.

Got it. Thanks.

-Sergey

> 
> > +F:	Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
> > +F:	Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> > +F:	drivers/ata/ahci_dwc.c
> > +
> >  LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
> >  M:	Mikael Pettersson <mikpelinux@gmail.com>
> >  L:	linux-ide@vger.kernel.org
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-04-11 12:11     ` Serge Semin
@ 2022-04-11 12:25       ` Damien Le Moal
  2022-04-11 20:52         ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-04-11 12:25 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On 4/11/22 21:11, Serge Semin wrote:
> On Thu, Mar 24, 2022 at 11:05:58AM +0900, Damien Le Moal wrote:
>> On 3/24/22 09:16, Serge Semin wrote:
>>> Currently there are four port-map-related fields declared in the
>>> ahci_host_priv structure and used to setup the HBA ports mapping. First
>>> the ports-mapping is read from the PI register and immediately stored in
>>> the saved_port_map field. If forced_port_map is initialized with non-zero
>>> value then its value will have greater priority over the value read from
>>> PI, thus it will override the saved_port_map field. That value will be then
>>> masked by a non-zero mask_port_map field and after some sanity checks it
>>> will be stored in the ahci_host_priv.port_map field as a final port
>>> mapping.
>>>
>>> As you can see the logic is a bit too complicated for such a simple task.
>>> We can freely get rid from at least one of the fields with no change to
>>> the implemented semantic. The force_port_map field can be replaced with
>>> taking non-zero saved_port_map value into account. So if saved_port_map is
>>> pre-initialized by the glue-driver/platform-specific code then it will
>>
> 
>> glue-driver == LLDD (low level device driver), for the entire series please.
> 
> Why? It's a normal term and well known amongst developers. I've used it
> in a plenty of my patches before and none of them has been questioned in that
> part so far.

This term is not used in libata, nor do I remember seeing it used in SCSI
or block subsystem either. We always talk about mid-layer (ahci platform)
and LLDD (adapter driver).

> 
> -Sergey
> 
>>
>>> have greater priority over the value read from PI register and will be
>>> used as actual HBA ports mapping later on. Thus the ports map forcing task
>>> will be just transferred from the force_port_map to saved_port_map field.
>>>
>>> This modification will perfectly fit into the feature of having OF-based
>>> initialization of the HW-init HBA CSR fields we are about to introduce in
>>> the next commit.
>>>
>>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
>>> ---
>>>  drivers/ata/ahci.c             |  2 +-
>>>  drivers/ata/ahci.h             |  1 -
>>>  drivers/ata/libahci.c          | 10 ++++++----
>>>  drivers/ata/libahci_platform.c |  2 +-
>>>  4 files changed, 8 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
>>> index ab5811ef5a53..8ce0d166cc8d 100644
>>> --- a/drivers/ata/ahci.c
>>> +++ b/drivers/ata/ahci.c
>>> @@ -654,7 +654,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
>>>  {
>>>  	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
>>>  		dev_info(&pdev->dev, "JMB361 has only one port\n");
>>> -		hpriv->force_port_map = 1;
>>> +		hpriv->saved_port_map = 1;
>>>  	}
>>>  
>>>  	/*
>>> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
>>> index 04690b4168a3..519d148ecaea 100644
>>> --- a/drivers/ata/ahci.h
>>> +++ b/drivers/ata/ahci.h
>>> @@ -329,7 +329,6 @@ struct ahci_port_priv {
>>>  struct ahci_host_priv {
>>>  	/* Input fields */
>>>  	unsigned int		flags;		/* AHCI_HFLAG_* */
>>> -	u32			force_port_map;	/* force port map */
>>>  	u32			mask_port_map;	/* mask out particular bits */
>>>  
>>>  	void __iomem *		mmio;		/* bus-independent mem map */
>>> diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
>>> index 0ed484e04fd6..011175e82174 100644
>>> --- a/drivers/ata/libahci.c
>>> +++ b/drivers/ata/libahci.c
>>> @@ -453,7 +453,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
>>>  	 * reset.  Values without are used for driver operation.
>>>  	 */
>>>  	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
>>> -	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
>>>  
>>>  	/* CAP2 register is only defined for AHCI 1.2 and later */
>>>  	vers = readl(mmio + HOST_VERSION);
>>> @@ -517,10 +516,13 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
>>>  		cap &= ~HOST_CAP_SXS;
>>>  	}
>>>  
>>> -	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
>>> +	/* Override the HBA ports mapping if the platform needs it */
>>> +	port_map = readl(mmio + HOST_PORTS_IMPL);
>>> +	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
>>>  		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
>>> -			 port_map, hpriv->force_port_map);
>>> -		port_map = hpriv->force_port_map;
>>> +			 port_map, hpriv->saved_port_map);
>>> +		port_map = hpriv->saved_port_map;
>>> +	} else {
>>>  		hpriv->saved_port_map = port_map;
>>>  	}
>>>  
>>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
>>> index febad33aa43c..5cbc2c42164d 100644
>>> --- a/drivers/ata/libahci_platform.c
>>> +++ b/drivers/ata/libahci_platform.c
>>> @@ -539,7 +539,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>>>  	}
>>>  
>>>  	of_property_read_u32(dev->of_node,
>>> -			     "ports-implemented", &hpriv->force_port_map);
>>> +			     "ports-implemented", &hpriv->saved_port_map);
>>>  
>>>  	if (child_nodes) {
>>>  		for_each_child_of_node(dev->of_node, child) {
>>
>>
>> -- 
>> Damien Le Moal
>> Western Digital Research


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
  2022-03-24  2:21   ` Damien Le Moal
@ 2022-04-11 12:41     ` Serge Semin
  2022-04-11 13:03       ` Damien Le Moal
  0 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-04-11 12:41 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 24, 2022 at 11:21:01AM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > Synopsys AHCI SATA controller can work pretty under with the generic
> > AHCI-platform driver control. But there are vendor-specific peculiarities
> > which can tune the device performance up and which may need to be fixed up
> > for proper device functioning. In addition some DWC AHCI-based controllers
> > may require small platform-specific fixups, so adding them in the generic
> > AHCI driver would have ruined the code simplicity. Shortly speaking in
> > order to keep the generic AHCI-platform code clean and have DWC AHCI
> > SATA-specific features supported we suggest to add a dedicated DWC AHCI
> > SATA device driver. Aside with the standard AHCI-platform resources
> > getting, enabling/disabling and the controller registration the new driver
> > performs the next actions.
> > 
> > First of all there is a way to verify whether the HBA/ports capabilities
> > activated in OF are correct. Almost all features availability is reflected
> > in the vendor-specific parameters registers. So the DWC AHCI driver does
> > the capabilities sanity check based on the corresponding fields state.
> > 
> > Secondly if either the Command Completion Coalescing or the Device Sleep
> > feature is enabled the DWC AHCI-specific internal 1ms timer must be fixed
> > in accordance with the application clock signal frequency. In particular
> > the timer value must be set to be Fapp * 1000. Normally the SoC designers
> > pre-configure the TIMER1MS register to contain a correct value by default.
> > But the platforms can support the application clock rate change. If that
> > happens the 1ms timer value must be accordingly updated otherwise the
> > dependent features won't work as expected. In the DWC AHCI driver we
> > suggest to rely on the "aclk" reference clock rate to set the timer
> > interval up. That clock source is supposed to be the AHCI SATA application
> > clock in accordance with the DT bindings.
> > 
> > Finally DWC AHCI SATA controller AXI/AHB bus DMA-engine can be tuned up to
> > transfer up to 1024 * FIFO words at a time by setting the Tx/Rx
> > transaction size in the DMA control register. The maximum value depends on
> > the DMA data bus and AXI/AHB bus maximum burst length. In most of the
> > cases it's better to set the maximum possible value to reach the best AHCI
> > SATA controller performance. But sometimes in order to improve the system
> > interconnect responsiveness, transferring in smaller data chunks may be
> > more preferable. For such cases and for the case when the default value
> > doesn't provide the best DMA bus performance we suggest to use the new
> > HBA-port specific DT-properties "snps,{tx,rx}-ts-max" to tune the DMA
> > transactions size up.
> > 
> > After all the settings denoted above are handled the DWC AHCI SATA driver
> > proceeds further with the standard AHCI-platform host initializations.
> > 
> > Note since DWC AHCI controller is now have a dedicated driver we can
> > discard the corresponding compatible string from the ahci-platform.c
> > module. The same concerns "snps,spear-ahci" compatible string, which is
> > also based on the DWC AHCI IP-core.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > Note there are three more AHCI SATA drivers which have been created for
> > the devices based on the DWC AHCI SATA IP-core. It's AHCI SunXi, St and
> > iMX drivers. Mostly they don't support the features implemented in this
> > driver. So hopefully sometime in future they can be converted to be based
> > on the generic DWC AHCI SATA driver and just perform some
> > subvendor-specific setups in their own glue-driver code. But for now
> > let's leave the generic DWC AHCI SATA code as is. Hopefully the new DWC
> > AHCI-based device drivers will try at least to re-use a part of the DWC
> > AHCI driver methods if not being able to be integrated in the generic
> > DWC driver code.
> > ---
> >  drivers/ata/Kconfig         |  10 +
> >  drivers/ata/Makefile        |   1 +
> >  drivers/ata/ahci_dwc.c      | 395 ++++++++++++++++++++++++++++++++++++
> >  drivers/ata/ahci_platform.c |   2 -
> >  4 files changed, 406 insertions(+), 2 deletions(-)
> >  create mode 100644 drivers/ata/ahci_dwc.c
> > 
> > diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> > index cb54631fd950..ab11bcf8510c 100644
> > --- a/drivers/ata/Kconfig
> > +++ b/drivers/ata/Kconfig
> > @@ -174,6 +174,16 @@ config AHCI_DM816
> >  
> >  	  If unsure, say N.
> >  
> > +config AHCI_DWC
> > +	tristate "Synopsys DWC AHCI SATA support"
> > +	select SATA_HOST
> > +	default SATA_AHCI_PLATFORM
> > +	help
> > +	  This option enables support for the Synopsys DWC AHCI SATA
> > +	  controller implementation.
> > +
> > +	  If unsure, say N.
> > +
> >  config AHCI_ST
> >  	tristate "ST AHCI SATA support"
> >  	depends on ARCH_STI
> > diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> > index b8aebfb14e82..34623365d9a6 100644
> > --- a/drivers/ata/Makefile
> > +++ b/drivers/ata/Makefile
> > @@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_DM816)	+= ahci_dm816.o libahci.o libahci_platform.o
> > +obj-$(CONFIG_AHCI_DWC)		+= ahci_dwc.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_IMX)		+= ahci_imx.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_MTK)		+= ahci_mtk.o libahci.o libahci_platform.o
> >  obj-$(CONFIG_AHCI_MVEBU)	+= ahci_mvebu.o libahci.o libahci_platform.o
> > diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
> > new file mode 100644
> > index 000000000000..c51e2251994e
> > --- /dev/null
> > +++ b/drivers/ata/ahci_dwc.c
> > @@ -0,0 +1,395 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * DWC AHCI SATA Platform driver
> > + *
> > + * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
> > + */
> > +
> > +#include <linux/ahci_platform.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <linux/clk.h>
> > +#include <linux/device.h>
> > +#include <linux/kernel.h>
> > +#include <linux/libata.h>
> > +#include <linux/log2.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm.h>
> > +
> > +#include "ahci.h"
> > +
> > +#define DRV_NAME "ahci-dwc"
> > +
> > +#define DWC_AHCI_FBS_PMPN_MAX		15
> 

> The convention is to name things starting with AHCI, e.g. AHCI_DWC_xxxx

I beg your pardon what convention? Is it defined in someplace of the
subsystem docs? If it's not then how should I know about that? These
are the device-specific macro. The static methods below are also
platform-specific and the standard kernel coding style doesn't specify
any rule about that. Moreover the most of the AHCI glue drivers (LLDD
like ahci_mtk.c, ahci_ceva.c, ahci_brcm.c, ahci_st.c, ahci_tegra.c,
ahci_xgene.c, etc) use the same prefixing style as I do here. Finally
the prefix reflects the actual device name "DWC AHCI". So if there is
no subsystem-specific restrictions I normally define the prefix in
that order for the sake of the clarity.

Note I don't mind to convert the code to being the way you ask, but if
it's really the AHCI-specific codying style convention then it would be
very useful to have it described/advertised in some place in the
kernel so to know about that beforehead for the developers reference.
So do you insist on switching the words order in the names prefix here?

> 
> > +
> > +/* DWC AHCI SATA controller specific registers */
> > +#define DWC_AHCI_HOST_OOBR		0xbc
> > +#define DWC_AHCI_HOST_OOB_WE		BIT(31)
> > +#define DWC_AHCI_HOST_CWMIN_MASK	GENMASK(30, 24)
> > +#define DWC_AHCI_HOST_CWMAX_MASK	GENMASK(23, 16)
> > +#define DWC_AHCI_HOST_CIMIN_MASK	GENMASK(15, 8)
> > +#define DWC_AHCI_HOST_CIMAX_MASK	GENMASK(7, 0)
> > +
> > +#define DWC_AHCI_HOST_GPCR		0xd0
> > +#define DWC_AHCI_HOST_GPSR		0xd4
> > +
> > +#define DWC_AHCI_HOST_TIMER1MS		0xe0
> > +#define DWC_AHCI_HOST_TIMV_MASK		GENMASK(19, 0)
> > +
> > +#define DWC_AHCI_HOST_GPARAM1R		0xe8
> > +#define DWC_AHCI_HOST_ALIGN_M		BIT(31)
> > +#define DWC_AHCI_HOST_RX_BUFFER		BIT(30)
> > +#define DWC_AHCI_HOST_PHY_DATA_MASK	GENMASK(29, 28)
> > +#define DWC_AHCI_HOST_PHY_RST		BIT(27)
> > +#define DWC_AHCI_HOST_PHY_CTRL_MASK	GENMASK(26, 21)
> > +#define DWC_AHCI_HOST_PHY_STAT_MASK	GENMASK(20, 15)
> > +#define DWC_AHCI_HOST_LATCH_M		BIT(14)
> > +#define DWC_AHCI_HOST_PHY_TYPE_MASK	GENMASK(13, 11)
> > +#define DWC_AHCI_HOST_RET_ERR		BIT(10)
> > +#define DWC_AHCI_HOST_AHB_ENDIAN_MASK	GENMASK(9, 8)
> > +#define DWC_AHCI_HOST_S_HADDR		BIT(7)
> > +#define DWC_AHCI_HOST_M_HADDR		BIT(6)
> > +#define DWC_AHCI_HOST_S_HDATA_MASK	GENMASK(5, 3)
> > +#define DWC_AHCI_HOST_M_HDATA_MASK	GENMASK(2, 0)
> > +
> > +#define DWC_AHCI_HOST_GPARAM2R		0xec
> > +#define DWC_AHCI_HOST_FBS_MEM_S		BIT(19)
> > +#define DWC_AHCI_HOST_FBS_PMPN_MASK	GENMASK(17, 16)
> > +#define DWC_AHCI_HOST_FBS_SUP		BIT(15)
> > +#define DWC_AHCI_HOST_DEV_CP		BIT(14)
> > +#define DWC_AHCI_HOST_DEV_MP		BIT(13)
> > +#define DWC_AHCI_HOST_ENCODE_M		BIT(12)
> > +#define DWC_AHCI_HOST_RXOOB_CLK_M	BIT(11)
> > +#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
> > +#define DWC_AHCI_HOST_TXOOB_M		BIT(9)
> > +#define DWC_AHCI_HOST_RXOOB_M		BIT(10)
> > +#define DWC_AHCI_HOST_RXOOB_CLK_MASK	GENMASK(8, 0)
> > +
> > +#define DWC_AHCI_HOST_PPARAMR		0xf0
> > +#define DWC_AHCI_HOST_TX_MEM_M		BIT(11)
> > +#define DWC_AHCI_HOST_TX_MEM_S		BIT(10)
> > +#define DWC_AHCI_HOST_RX_MEM_M		BIT(9)
> > +#define DWC_AHCI_HOST_RX_MEM_S		BIT(8)
> > +#define DWC_AHCI_HOST_TXFIFO_DEPTH	GENMASK(7, 4)
> > +#define DWC_AHCI_HOST_RXFIFO_DEPTH	GENMASK(3, 0)
> > +
> > +#define DWC_AHCI_HOST_TESTR		0xf4
> > +#define DWC_AHCI_HOST_PSEL_MASK		GENMASK(18, 16)
> > +#define DWC_AHCI_HOST_TEST_IF		BIT(0)
> > +
> > +#define DWC_AHCI_HOST_VERSIONR		0xf8
> > +#define DWC_AHCI_HOST_IDR		0xfc
> > +
> > +#define DWC_AHCI_PORT_DMACR		0x70
> > +#define DWC_AHCI_PORT_RXABL_MASK	GENMASK(15, 12)
> > +#define DWC_AHCI_PORT_TXABL_MASK	GENMASK(11, 8)
> > +#define DWC_AHCI_PORT_RXTS_MASK		GENMASK(7, 4)
> > +#define DWC_AHCI_PORT_TXTS_MASK		GENMASK(3, 0)
> > +#define DWC_AHCI_PORT_PHYCR		0x74
> > +#define DWC_AHCI_PORT_PHYSR		0x78
> > +
> > +struct dwc_ahci_host_priv {
> > +	struct platform_device *pdev;
> > +
> > +	u32 timv;
> > +	u32 dmacr[AHCI_MAX_PORTS];
> > +};
> > +
> > +static struct ahci_host_priv *dwc_ahci_get_resources(struct platform_device *pdev)
> 

> Same: dwc_ahci_get_resources() -> ahci_dwc_get_resources()

Please see my previous comment.

-Sergey

> 
> > +{
> > +	struct dwc_ahci_host_priv *dpriv;
> > +	struct ahci_host_priv *hpriv;
> > +
> > +	dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);
> > +	if (!dpriv)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	dpriv->pdev = pdev;
> > +
> > +	hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
> > +	if (IS_ERR(hpriv))
> > +		return hpriv;
> > +
> > +	hpriv->plat_data = (void *)dpriv;
> > +
> > +	return hpriv;
> > +}
> > +
> > +static void dwc_ahci_check_cap(struct ahci_host_priv *hpriv)
> > +{
> > +	unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
> > +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> > +	bool dev_mp, dev_cp, fbs_sup;
> > +	unsigned int fbs_pmp;
> > +	u32 param;
> > +	int i;
> > +
> > +	param = readl(hpriv->mmio + DWC_AHCI_HOST_GPARAM2R);
> > +	dev_mp = !!(param & DWC_AHCI_HOST_DEV_MP);
> > +	dev_cp = !!(param & DWC_AHCI_HOST_DEV_CP);
> > +	fbs_sup = !!(param & DWC_AHCI_HOST_FBS_SUP);
> > +	fbs_pmp = 5 * FIELD_GET(DWC_AHCI_HOST_FBS_PMPN_MASK, param);
> > +
> > +	if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {
> > +		dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");
> > +		hpriv->saved_cap &= ~HOST_CAP_MPS;
> > +	}
> > +
> > +
> > +	if (fbs_sup && fbs_pmp < DWC_AHCI_FBS_PMPN_MAX) {
> > +		dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",
> > +			 fbs_pmp);
> > +	}
> > +
> > +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> > +		if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {
> > +			dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);
> > +			hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;
> > +		}
> > +
> > +		if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {
> > +			dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);
> > +			hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;
> > +		}
> > +
> > +		if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {
> > +			dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);
> > +			hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;
> > +		}
> > +	}
> > +}
> > +
> > +static void dwc_ahci_init_timer(struct ahci_host_priv *hpriv)
> > +{
> > +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> > +	unsigned long rate;
> > +	struct clk *aclk;
> > +	u32 cap, cap2;
> > +
> > +	/* 1ms tick is generated only for the CCC or DevSleep features */
> > +	cap = readl(hpriv->mmio + HOST_CAP);
> > +	cap2 = readl(hpriv->mmio + HOST_CAP2);
> > +	if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))
> > +		return;
> > +
> > +	/*
> > +	 * Tick is generated based on the AXI/AHB application clocks signal
> > +	 * so we need to be sure in the clock we are going to use.
> > +	 */
> > +	aclk = ahci_platform_find_clk(hpriv, "aclk");
> > +	if (!aclk)
> > +		return;
> > +
> > +	/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */
> > +	dpriv->timv = readl(hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> > +	dpriv->timv = FIELD_GET(DWC_AHCI_HOST_TIMV_MASK, dpriv->timv);
> > +	rate = clk_get_rate(aclk) / 1000UL;
> > +	if (rate == dpriv->timv)
> > +		return;
> > +
> > +	dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",
> > +		 rate / 1000UL);
> > +	dpriv->timv = FIELD_PREP(DWC_AHCI_HOST_TIMV_MASK, rate);
> > +	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> > +}
> > +
> > +static int dwc_ahci_init_dmacr(struct ahci_host_priv *hpriv)
> > +{
> > +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> > +	struct device_node *child;
> > +	void __iomem *port_mmio;
> > +	u32 port, dmacr, ts;
> > +
> > +	/*
> > +	 * Update the DMA Tx/Rx transaction sizes in accordance with the
> > +	 * platform setup. Note values exceeding maximal or minimal limits will
> > +	 * be automatically clamped. Also note the register isn't affected by
> > +	 * the HBA global reset so we can freely initialize it once until the
> > +	 * next system reset.
> > +	 */
> > +	for_each_child_of_node(dpriv->pdev->dev.of_node, child) {
> > +		if (!of_device_is_available(child))
> > +			continue;
> > +
> > +		if (of_property_read_u32(child, "reg", &port)) {
> > +			of_node_put(child);
> > +			return -EINVAL;
> > +		}
> > +
> > +		port_mmio = __ahci_port_base(hpriv, port);
> > +		dmacr = readl(port_mmio + DWC_AHCI_PORT_DMACR);
> > +
> > +		if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
> > +			ts = ilog2(ts);
> > +			dmacr &= ~DWC_AHCI_PORT_TXTS_MASK;
> > +			dmacr |= FIELD_PREP(DWC_AHCI_PORT_TXTS_MASK, ts);
> > +		}
> > +
> > +		if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
> > +			ts = ilog2(ts);
> > +			dmacr &= ~DWC_AHCI_PORT_RXTS_MASK;
> > +			dmacr |= FIELD_PREP(DWC_AHCI_PORT_RXTS_MASK, ts);
> > +		}
> > +
> > +		writel(dmacr, port_mmio + DWC_AHCI_PORT_DMACR);
> > +		dpriv->dmacr[port] = dmacr;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dwc_ahci_init_host(struct ahci_host_priv *hpriv)
> > +{
> > +	int rc;
> > +
> > +	rc = ahci_platform_enable_resources(hpriv);
> > +	if (rc)
> > +		return rc;
> > +
> > +	dwc_ahci_check_cap(hpriv);
> > +
> > +	dwc_ahci_init_timer(hpriv);
> > +
> > +	rc = dwc_ahci_init_dmacr(hpriv);
> > +	if (rc)
> > +		goto err_disable_resources;
> > +
> > +	return 0;
> > +
> > +err_disable_resources:
> > +	ahci_platform_disable_resources(hpriv);
> > +
> > +	return rc;
> > +}
> > +
> > +static int dwc_ahci_reinit_host(struct ahci_host_priv *hpriv)
> > +{
> > +	struct dwc_ahci_host_priv *dpriv = hpriv->plat_data;
> > +	unsigned long port_map = hpriv->port_map;
> > +	void __iomem *port_mmio;
> > +	int i, rc;
> > +
> > +	rc = ahci_platform_enable_resources(hpriv);
> > +	if (rc)
> > +		return rc;
> > +
> > +	writel(dpriv->timv, hpriv->mmio + DWC_AHCI_HOST_TIMER1MS);
> > +
> > +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> > +		port_mmio = __ahci_port_base(hpriv, i);
> > +		writel(dpriv->dmacr[i], port_mmio + DWC_AHCI_PORT_DMACR);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void dwc_ahci_clear_host(struct ahci_host_priv *hpriv)
> > +{
> > +	ahci_platform_disable_resources(hpriv);
> > +}
> > +
> > +static void dwc_ahci_stop_host(struct ata_host *host)
> > +{
> > +	struct ahci_host_priv *hpriv = host->private_data;
> > +
> > +	dwc_ahci_clear_host(hpriv);
> > +}
> > +
> > +static struct ata_port_operations dwc_ahci_port_ops = {
> > +	.inherits	= &ahci_platform_ops,
> > +	.host_stop	= dwc_ahci_stop_host,
> > +};
> > +
> > +static const struct ata_port_info dwc_ahci_port_info = {
> > +	.flags		= AHCI_FLAG_COMMON,
> > +	.pio_mask	= ATA_PIO4,
> > +	.udma_mask	= ATA_UDMA6,
> > +	.port_ops	= &dwc_ahci_port_ops,
> > +};
> > +
> > +static struct scsi_host_template dwc_ahci_scsi_info = {
> > +	AHCI_SHT(DRV_NAME),
> > +};
> > +
> > +static int dwc_ahci_probe(struct platform_device *pdev)
> > +{
> > +	struct ahci_host_priv *hpriv;
> > +	int rc;
> > +
> > +	hpriv = dwc_ahci_get_resources(pdev);
> > +	if (IS_ERR(hpriv))
> > +		return PTR_ERR(hpriv);
> > +
> > +	rc = dwc_ahci_init_host(hpriv);
> > +	if (rc)
> > +		return rc;
> > +
> > +	rc = ahci_platform_init_host(pdev, hpriv, &dwc_ahci_port_info,
> > +				     &dwc_ahci_scsi_info);
> > +	if (rc)
> > +		goto err_clear_host;
> > +
> > +	return 0;
> > +
> > +err_clear_host:
> > +	dwc_ahci_clear_host(hpriv);
> > +
> > +	return rc;
> > +}
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int dwc_ahci_suspend(struct device *dev)
> > +{
> > +	struct ata_host *host = dev_get_drvdata(dev);
> > +	struct ahci_host_priv *hpriv = host->private_data;
> > +	int rc;
> > +
> > +	rc = ahci_platform_suspend_host(dev);
> > +	if (rc)
> > +		return rc;
> > +
> > +	dwc_ahci_clear_host(hpriv);
> > +
> > +	return 0;
> > +}
> > +
> > +static int dwc_ahci_resume(struct device *dev)
> > +{
> > +	struct ata_host *host = dev_get_drvdata(dev);
> > +	struct ahci_host_priv *hpriv = host->private_data;
> > +	int rc;
> > +
> > +	rc = dwc_ahci_reinit_host(hpriv);
> > +	if (rc)
> > +		return rc;
> > +
> > +	return ahci_platform_resume_host(dev);
> > +}
> > +#endif
> > +
> > +static SIMPLE_DEV_PM_OPS(dwc_ahci_pm_ops, dwc_ahci_suspend, dwc_ahci_resume);
> > +
> > +static const struct of_device_id dwc_ahci_of_match[] = {
> > +	{ .compatible = "snps,dwc-ahci", },
> > +	{ .compatible = "snps,spear-ahci", },
> > +	{},
> > +};
> > +MODULE_DEVICE_TABLE(of, dwc_ahci_of_match);
> > +
> > +static struct platform_driver dwc_ahci_driver = {
> > +	.probe = dwc_ahci_probe,
> > +	.remove = ata_platform_remove_one,
> > +	.shutdown = ahci_platform_shutdown,
> > +	.driver = {
> > +		.name = DRV_NAME,
> > +		.of_match_table = dwc_ahci_of_match,
> > +		.pm = &dwc_ahci_pm_ops,
> > +	},
> > +};
> > +module_platform_driver(dwc_ahci_driver);
> > +
> > +MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
> > +MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
> > index 24c25f076f37..052eaa30d262 100644
> > --- a/drivers/ata/ahci_platform.c
> > +++ b/drivers/ata/ahci_platform.c
> > @@ -80,9 +80,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
> >  static const struct of_device_id ahci_of_match[] = {
> >  	{ .compatible = "generic-ahci", },
> >  	/* Keep the following compatibles for device tree compatibility */
> > -	{ .compatible = "snps,spear-ahci", },
> >  	{ .compatible = "ibm,476gtr-ahci", },
> > -	{ .compatible = "snps,dwc-ahci", },
> >  	{ .compatible = "hisilicon,hisi-ahci", },
> >  	{ .compatible = "cavium,octeon-7130-ahci", },
> >  	{},
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
  2022-04-11 12:41     ` Serge Semin
@ 2022-04-11 13:03       ` Damien Le Moal
  2022-04-11 20:41         ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-04-11 13:03 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On 4/11/22 21:41, Serge Semin wrote:
> I beg your pardon what convention? Is it defined in someplace of the
> subsystem docs? If it's not then how should I know about that? These
> are the device-specific macro. The static methods below are also
> platform-specific and the standard kernel coding style doesn't specify
> any rule about that. Moreover the most of the AHCI glue drivers (LLDD
> like ahci_mtk.c, ahci_ceva.c, ahci_brcm.c, ahci_st.c, ahci_tegra.c,
> ahci_xgene.c, etc) use the same prefixing style as I do here. Finally
> the prefix reflects the actual device name "DWC AHCI". So if there is
> no subsystem-specific restrictions I normally define the prefix in
> that order for the sake of the clarity.

Look at how other ahci drivers have named things. That's the "convention"
I am talking about. Most of them name things ahci_xxx_... Same for macros.

> 
> Note I don't mind to convert the code to being the way you ask, but if
> it's really the AHCI-specific codying style convention then it would be
> very useful to have it described/advertised in some place in the
> kernel so to know about that beforehead for the developers reference.
> So do you insist on switching the words order in the names prefix here?

It is nice to have code consistency in the naming. That always facilitate
grepping the code.


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number
  2022-03-24  8:13       ` Damien Le Moal
@ 2022-04-11 13:10         ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 13:10 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Sergey Shtylyov, Serge Semin, Hans de Goede, Jens Axboe,
	Alexey Malahov, Pavel Parkhomenko, Rob Herring, linux-ide,
	linux-kernel, devicetree

On Thu, Mar 24, 2022 at 05:13:45PM +0900, Damien Le Moal wrote:
> On 3/24/22 17:12, Sergey Shtylyov wrote:
> > On 3/24/22 4:40 AM, Damien Le Moal wrote:
> > 
> >>> Having greater than (AHCI_MAX_PORTS = 32) ports detected isn't that
> >>> critical from the further AHCI-platform initialization point of view since
> >>> exceeding the ports upper limit will cause allocating more resources than
> >>> will be used afterwards. But detecting too many child DT-nodes doesn't
> >>> seem right since it's very unlikely to have it on an ordinary platform. In
> >>> accordance with the AHCI specification there can't be more than 32 ports
> >>> implemented at least due to having the CAP.NP field of 4 bits wide and the
> >>> PI register of dword size. Thus if such situation is found the DTB must
> >>> have been corrupted and the data read from it shouldn't be reliable. Let's
> >>> consider that as an erroneous situation and halt further resources
> >>> allocation.
> >>>
> >>> Note it's logically more correct to have the nports set only after the
> >>> initialization value is checked for being sane. So while at it let's make
> >>> sure nports is assigned with a correct value.
> >>>
> >>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> >>> ---
> >>>  drivers/ata/libahci_platform.c | 16 +++++++++++-----
> >>>  1 file changed, 11 insertions(+), 5 deletions(-)
> >>>
> >>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> >>> index 4fb9629c03ab..845042295b97 100644
> >>> --- a/drivers/ata/libahci_platform.c
> >>> +++ b/drivers/ata/libahci_platform.c
> >>> @@ -470,15 +470,21 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >>>  		}
> >>>  	}
> >>>  
> >>> -	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
> >>> -
> >>>  	/*
> >>> -	 * If no sub-node was found, we still need to set nports to
> >>> -	 * one in order to be able to use the
> >>> +	 * Too many sub-nodes most likely means having something wrong with
> >>> +	 * firmware. If no sub-node was found, we still need to set nports
> >>> +	 * to one in order to be able to use the
> >>>  	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
> >>>  	 */

> >>> -	if (!child_nodes)
> >>> +	child_nodes = of_get_child_count(dev->of_node);
> >>> +	if (child_nodes > AHCI_MAX_PORTS) {
> >>> +		rc = -EINVAL;
> >>> +		goto err_out;
> >>> +	} else if (!child_nodes) {
> >>
> >> No need for "else" after a return.
> > 
> >    You meant *goto*? :-)
> 
> Yes :) No need for the else after goto.

Personally I prefer having the chained if-else-if-else-etc statement
in such cases from readability and maintainability points of view (it
makes the code reader to more easily perceive that all the variable
value ranges are covered with no reference to the if-else clause
statements). But in this particular case dropping the else word lets
us to convert the afterwards statement into a single line
+	hpriv->nports = child_nodes ?: 1;
So why not. I'll drop 'else' from there then.

-Sergey

> 
> > 
> > [...]
> > 
> > MBR, Sergey
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports
  2022-03-29  8:15   ` Damien Le Moal
@ 2022-04-11 19:25     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 19:25 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Rob Herring,
	Linus Walleij, Alexey Malahov, Pavel Parkhomenko, linux-ide,
	linux-kernel, devicetree

On Tue, Mar 29, 2022 at 05:15:12PM +0900, Damien Le Moal wrote:
> On 3/24/22 09:16, Serge Semin wrote:
> > The denoted in the description upper limit only concerns the Port
> > Multipliers, but not the actual SATA ports. It's an external device
> > attached to a SATA port in order to access more than one SATA-drive. So
> > when it's attached to a SATA port it just extends the port capability
> > while the number of actual SATA ports stays the same. For instance on AHCI
> > controllers the number of actual ports is determined by the CAP.NP field
> > and the PI (Ports Implemented) register. AFAICS in general the maximum
> > number of SATA ports depends on the particular controller implementation.
> > Generic AHCI controller can't have more than 32 ports (since CAP.NP is of
> > 5 bits wide and PI register is 32-bits size), while DWC AHCI SATA
> > controller can't be configured with more than 8 ports activated. So let's
> > discard the SATA ports reg-property restrictions and just make sure that
> > it consists of a single reg-item.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  Documentation/devicetree/bindings/ata/sata-common.yaml | 7 +++----
> >  1 file changed, 3 insertions(+), 4 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/ata/sata-common.yaml b/Documentation/devicetree/bindings/ata/sata-common.yaml
> > index 7ac77b1c5850..c619f0ae72fb 100644
> > --- a/Documentation/devicetree/bindings/ata/sata-common.yaml
> > +++ b/Documentation/devicetree/bindings/ata/sata-common.yaml
> > @@ -41,11 +41,10 @@ patternProperties:
> >      properties:
> >        reg:
> >          minimum: 0
> > -        maximum: 14
> 

> Why remove this ? Since AHCI can have up to 32 ports, then change the
> value to 31. As the comment at the top of the file says, this is not
> intended to be a device tree binding spec, but defines properties common
> to most adapters.

Right, but the schema determines the common !SATA! controllers properties,
while you are referring to the AHCI-specific limit. As I said in the patch
log AFAICS in general the SATA controllers may have any number of ports.
The number is determined by the hardware designers needs only. Thus the
actual constraints needs to be specified in the controller-specific
YAML-schema (the one which will $ref to sata-common.yaml).

Though I couldn't find any ATA device driver in the kernel which would
handle a device with even 32 ports, not to mention a greater number.
So replacing it with 31 might be reasonable after all. But me failing
to find any such device doesn't me it can't exist. Thus I've decided to
drop the upper limit completely.

> 
> >          description:
> > -          The ID number of the drive port SATA can potentially use a port
> > -          multiplier making it possible to connect up to 15 disks to a single
> > -          SATA port.
> > +          The ID number of the SATA port. Aside with being directly used
> > +          each port can have a Port Multiplier attached thus allowing to
> > +          access more than one drive by means of a single channel.
> 

> Please add a comma after "Aside with being directly used", otherwise the
> sentence is hard to understand. And replace "channel" with "SATA port" to
> stick with the terms defined here.

Ok.

-Sergey

> 
> >  
> >  additionalProperties: true
> >  
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema
  2022-03-28 19:32   ` Rob Herring
@ 2022-04-11 19:34     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 19:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Damien Le Moal, Hans de Goede, Jens Axboe,
	Alexey Malahov, Pavel Parkhomenko,
	open list:LIBATA SUBSYSTEM (Serial and Parallel ATA drivers),
	linux-kernel, devicetree

On Mon, Mar 28, 2022 at 02:32:06PM -0500, Rob Herring wrote:
> On Wed, Mar 23, 2022 at 7:16 PM Serge Semin
> <Sergey.Semin@baikalelectronics.ru> wrote:
> >
> > Currently the DT bindings of Generic AHCI Controllers are described by
> > means of the legacy text file. Since such format is deprecated in favor of
> > the DT schema. Let's convert the Generic AHCI Controllers bindings file
> > then to the corresponding yaml files. There will be two of them: a DT
> > schema with a set of properties applied to all AHCI-compatible devices,
> > and a DT schema validating an AHCI-controller on a generic platform. So if
> > a controller conforms to the Serial ATA AHCI interface specification with
> > just peculiar platform environment settings like clock sources, PHYs,
> > power regulators or resets, then the generic AHCI bindings should work for
> > it. Otherwise a dedicated DT-schema needs to be created.
> >
> > So a common AHCI SATA controller DT-node is supposed to be equipped with
> > at least compatible, reg and interrupts properties. It can optionally
> > contain clocks, resets, {ahci,target,phy}-supply and phys phandles. In
> > addition the property "ports-implemented" can be specified in order to
> > define the number of implemented SATA ports. An AHCI SATA controller
> > DT-node can also have a set of sub-nodes representing its ports, for each
> > of which an individual power source and PHY phandle can be specified.
> >
> > Note we have omitted the next compatible strings
> > "marvell,armada-380-ahci", "marvell,armada-3700-ahci", "snps,dwc-ahci",
> > "snps,spear-ahci" since the corresponding controllers are handled by the
> > dedicated drivers now, thus are supposed to have their own DT-schema
> > defined. dma-coherent has also been discarded since it's a generic
> > property and is evaluated by the dt-schema parser.
> >
> > Also note that if there is the "reg-names" property specified for a AHCI
> > DT-node then it is supposed to at least have the "ahci" sub-string as an
> > indicator of the AHCI-compatible registers space.
> >
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  .../devicetree/bindings/ata/ahci-common.yaml  | 110 ++++++++++++++++++
> >  .../devicetree/bindings/ata/ahci-platform.txt |  79 -------------
> >  .../devicetree/bindings/ata/generic-ahci.yaml |  89 ++++++++++++++
> >  3 files changed, 199 insertions(+), 79 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/ata/ahci-common.yaml
> >  delete mode 100644 Documentation/devicetree/bindings/ata/ahci-platform.txt
> >  create mode 100644 Documentation/devicetree/bindings/ata/generic-ahci.yaml
> 

> This has already been converted and is in Linus' tree now for v5.18.

Too bad.( I'll have to rebase this patch on top of that schema now
seeing it hasn't been split up into the common and platform-specific
parts.

-Sergey

> 
> Rob

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

* Re: [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
  2022-04-01  0:06   ` Rob Herring
@ 2022-04-11 20:00     ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 20:00 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Damien Le Moal, Hans de Goede, Jens Axboe,
	Alexey Malahov, Pavel Parkhomenko, linux-ide, linux-kernel,
	devicetree

On Thu, Mar 31, 2022 at 07:06:27PM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 03:16:23AM +0300, Serge Semin wrote:
> > Synopsys AHCI SATA controller is mainly compatible with the generic AHCI
> > SATA controller except a few peculiarities and the platform environment
> > requirements. In particular it can have one or two reference clocks to
> > feed up its AXI/AHB interface and SATA PHYs domain and at least one reset
> > control for the application clock domain. In addition to that the DMA
> > interface of each port can be tuned up to work with the predefined maximum
> > data chunk size. Note unlike generic AHCI controller DWC AHCI can't have
> > more than 8 ports. All of that is reflected in the new DWC AHCI SATA
> > device DT binding.
> > 
> > Note the DWC AHCI SATA controller DT-schema has been created in a way so
> > to be reused for the vendor-specific DT-schemas. One of which we are about
> > to introduce.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  .../bindings/ata/snps,dwc-ahci.yaml           | 121 ++++++++++++++++++
> >  1 file changed, 121 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> > new file mode 100644
> > index 000000000000..b443154b63aa
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
> > @@ -0,0 +1,121 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/ata/snps,dwc-ahci.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Synopsys DWC AHCI SATA controller
> > +
> > +maintainers:
> > +  - Serge Semin <fancer.lancer@gmail.com>
> > +
> > +description: |
> > +  This document defines device tree bindings for the Synopsys DWC
> > +  implementation of the AHCI SATA controller.
> > +
> > +allOf:
> > +  - $ref: ahci-common.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    oneOf:
> > +      - description: Synopsys AHCI SATA-compatible devices
> > +        contains:
> > +          const: snps,dwc-ahci
> > +      - description: SPEAr1340 AHCI SATA device
> > +        const: snps,spear-ahci
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    description:
> > +      Basic DWC AHCI SATA clock sources like application AXI/AHB BIU clock
> > +      and embedded PHYs reference clock together with vendor-specific set
> > +      of clocks.
> > +    minItems: 1
> > +    maxItems: 4
> > +
> > +  clock-names:
> > +    contains:
> > +      anyOf:
> > +        - description: Application AXI/AHB BIU clock source
> > +          enum:
> > +            - aclk
> > +            - sata
> > +        - description: SATA Ports reference clock
> > +          enum:
> > +            - ref
> > +            - sata_ref
> > +
> > +  resets:
> > +    description:
> > +      At least basic core and application clock domains reset is normally
> > +      supported by the DWC AHCI SATA controller. Some platform specific
> > +      clocks can be also specified though.
> > +
> > +  reset-names:
> > +    contains:
> > +      description: Core and application clock domains reset control
> > +      const: arst
> > +
> > +patternProperties:
> > +  "^sata-port@[0-9a-e]$":
> > +    type: object
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 7
> > +
> > +      snps,tx-ts-max:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description: Maximal size of Tx DMA transactions in FIFO words
> > +        minimum: 1
> > +        maximum: 1024
> > +
> > +      snps,rx-ts-max:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description: Maximal size of Rx DMA transactions in FIFO words
> > +        minimum: 1
> > +        maximum: 1024
> 

> Are you reading these somewhere? 

Yes I do read them in the DWC AHCI driver and use ilog2() to get
the corresponding power of two value.

> 
> Only powers of 2 are valid. (Guess what Calxeda's controller uses.)

Right and is limited to be within [1; 1024]. Do you suggest to add a
respective comment in the description or just manually enumerate the
POW2 values? I don't believe there is a ready-to-use power-of-2 type in
the /schemas/types.yaml file. BTW what about adding one seeing there are
many cases where it could be useful?

-Sergey

> 
> Rob

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

* Re: [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support
  2022-04-11 13:03       ` Damien Le Moal
@ 2022-04-11 20:41         ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-11 20:41 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Mon, Apr 11, 2022 at 10:03:27PM +0900, Damien Le Moal wrote:
> On 4/11/22 21:41, Serge Semin wrote:
> > I beg your pardon what convention? Is it defined in someplace of the
> > subsystem docs? If it's not then how should I know about that? These
> > are the device-specific macro. The static methods below are also
> > platform-specific and the standard kernel coding style doesn't specify
> > any rule about that. Moreover the most of the AHCI glue drivers (LLDD
> > like ahci_mtk.c, ahci_ceva.c, ahci_brcm.c, ahci_st.c, ahci_tegra.c,
> > ahci_xgene.c, etc) use the same prefixing style as I do here. Finally
> > the prefix reflects the actual device name "DWC AHCI". So if there is
> > no subsystem-specific restrictions I normally define the prefix in
> > that order for the sake of the clarity.
> 

> Look at how other ahci drivers have named things. That's the "convention"
> I am talking about. Most of them name things ahci_xxx_... Same for macros.

Looked. Way not the most of them. Here are the other drivers with the
naming like I used in this patch:
ahci_mtk.c, ahci_ceva.c, ahci_brcm.c, ahci_st.c, ahci_tegra.c,
ahci_xgene.c, ahci_imx.c, etc.
That's almost half of all the AHCI drivers. Really how could I have
possibly figure out that there is a convention if so many drivers
don't have it followed?..

> 
> > 
> > Note I don't mind to convert the code to being the way you ask, but if
> > it's really the AHCI-specific codying style convention then it would be
> > very useful to have it described/advertised in some place in the
> > kernel so to know about that beforehead for the developers reference.
> > So do you insist on switching the words order in the names prefix here?
> 

> It is nice to have code consistency in the naming. That always facilitate
> grepping the code.

I am with both my hands for it, but that naming consistency must be
thoroughly documented in some place of the kernel or at least the
"convention" must be logically derivable from the existing code. It
would spare my, the other developers and actually the maintainers
time. Do you suggest to thoroughly scan each AHCI driver in the
subsystem to figure it out? Even if I did that the only way to come up
with an idea that there is a naming convention would be only if I
expected that there is one, but seeing it's a first time I've met such
LLDD requirement (really, no kernel subsystem has such naming
convention applied for the glue-drivers) and almost half of the AHCI
drivers not following the convention while the other half following it
just partly. Judging by that, neither me nor many other developer had
a chance to create an acceptable code from scratch.

-Sergey

> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-04-11 12:25       ` Damien Le Moal
@ 2022-04-11 20:52         ` Serge Semin
  2022-04-11 22:48           ` Damien Le Moal
  0 siblings, 1 reply; 65+ messages in thread
From: Serge Semin @ 2022-04-11 20:52 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Mon, Apr 11, 2022 at 09:25:03PM +0900, Damien Le Moal wrote:
> On 4/11/22 21:11, Serge Semin wrote:
> > On Thu, Mar 24, 2022 at 11:05:58AM +0900, Damien Le Moal wrote:
> >> On 3/24/22 09:16, Serge Semin wrote:
> >>> Currently there are four port-map-related fields declared in the
> >>> ahci_host_priv structure and used to setup the HBA ports mapping. First
> >>> the ports-mapping is read from the PI register and immediately stored in
> >>> the saved_port_map field. If forced_port_map is initialized with non-zero
> >>> value then its value will have greater priority over the value read from
> >>> PI, thus it will override the saved_port_map field. That value will be then
> >>> masked by a non-zero mask_port_map field and after some sanity checks it
> >>> will be stored in the ahci_host_priv.port_map field as a final port
> >>> mapping.
> >>>
> >>> As you can see the logic is a bit too complicated for such a simple task.
> >>> We can freely get rid from at least one of the fields with no change to
> >>> the implemented semantic. The force_port_map field can be replaced with
> >>> taking non-zero saved_port_map value into account. So if saved_port_map is
> >>> pre-initialized by the glue-driver/platform-specific code then it will
> >>
> > 
> >> glue-driver == LLDD (low level device driver), for the entire series please.
> > 
> > Why? It's a normal term and well known amongst developers. I've used it
> > in a plenty of my patches before and none of them has been questioned in that
> > part so far.
> 

> This term is not used in libata, nor do I remember seeing it used in SCSI
> or block subsystem either. We always talk about mid-layer (ahci platform)
> and LLDD (adapter driver).

Great, do we need to learn the subsystem-specific dictionary now
before submitting the patches for it? =)
Really, you are asking me to change one term to its synonym just
because it's mainly unused here. Now you know what it means, the
others can easily google it and get to learn something new. Win-win.)

-Sergey

> 
> > 
> > -Sergey
> > 
> >>
> >>> have greater priority over the value read from PI register and will be
> >>> used as actual HBA ports mapping later on. Thus the ports map forcing task
> >>> will be just transferred from the force_port_map to saved_port_map field.
> >>>
> >>> This modification will perfectly fit into the feature of having OF-based
> >>> initialization of the HW-init HBA CSR fields we are about to introduce in
> >>> the next commit.
> >>>
> >>> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> >>> ---
> >>>  drivers/ata/ahci.c             |  2 +-
> >>>  drivers/ata/ahci.h             |  1 -
> >>>  drivers/ata/libahci.c          | 10 ++++++----
> >>>  drivers/ata/libahci_platform.c |  2 +-
> >>>  4 files changed, 8 insertions(+), 7 deletions(-)
> >>>
> >>> diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
> >>> index ab5811ef5a53..8ce0d166cc8d 100644
> >>> --- a/drivers/ata/ahci.c
> >>> +++ b/drivers/ata/ahci.c
> >>> @@ -654,7 +654,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
> >>>  {
> >>>  	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
> >>>  		dev_info(&pdev->dev, "JMB361 has only one port\n");
> >>> -		hpriv->force_port_map = 1;
> >>> +		hpriv->saved_port_map = 1;
> >>>  	}
> >>>  
> >>>  	/*
> >>> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> >>> index 04690b4168a3..519d148ecaea 100644
> >>> --- a/drivers/ata/ahci.h
> >>> +++ b/drivers/ata/ahci.h
> >>> @@ -329,7 +329,6 @@ struct ahci_port_priv {
> >>>  struct ahci_host_priv {
> >>>  	/* Input fields */
> >>>  	unsigned int		flags;		/* AHCI_HFLAG_* */
> >>> -	u32			force_port_map;	/* force port map */
> >>>  	u32			mask_port_map;	/* mask out particular bits */
> >>>  
> >>>  	void __iomem *		mmio;		/* bus-independent mem map */
> >>> diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
> >>> index 0ed484e04fd6..011175e82174 100644
> >>> --- a/drivers/ata/libahci.c
> >>> +++ b/drivers/ata/libahci.c
> >>> @@ -453,7 +453,6 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
> >>>  	 * reset.  Values without are used for driver operation.
> >>>  	 */
> >>>  	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
> >>> -	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
> >>>  
> >>>  	/* CAP2 register is only defined for AHCI 1.2 and later */
> >>>  	vers = readl(mmio + HOST_VERSION);
> >>> @@ -517,10 +516,13 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
> >>>  		cap &= ~HOST_CAP_SXS;
> >>>  	}
> >>>  
> >>> -	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
> >>> +	/* Override the HBA ports mapping if the platform needs it */
> >>> +	port_map = readl(mmio + HOST_PORTS_IMPL);
> >>> +	if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
> >>>  		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
> >>> -			 port_map, hpriv->force_port_map);
> >>> -		port_map = hpriv->force_port_map;
> >>> +			 port_map, hpriv->saved_port_map);
> >>> +		port_map = hpriv->saved_port_map;
> >>> +	} else {
> >>>  		hpriv->saved_port_map = port_map;
> >>>  	}
> >>>  
> >>> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> >>> index febad33aa43c..5cbc2c42164d 100644
> >>> --- a/drivers/ata/libahci_platform.c
> >>> +++ b/drivers/ata/libahci_platform.c
> >>> @@ -539,7 +539,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
> >>>  	}
> >>>  
> >>>  	of_property_read_u32(dev->of_node,
> >>> -			     "ports-implemented", &hpriv->force_port_map);
> >>> +			     "ports-implemented", &hpriv->saved_port_map);
> >>>  
> >>>  	if (child_nodes) {
> >>>  		for_each_child_of_node(dev->of_node, child) {
> >>
> >>
> >> -- 
> >> Damien Le Moal
> >> Western Digital Research
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-04-11 20:52         ` Serge Semin
@ 2022-04-11 22:48           ` Damien Le Moal
  2022-04-12 12:29             ` Serge Semin
  0 siblings, 1 reply; 65+ messages in thread
From: Damien Le Moal @ 2022-04-11 22:48 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On 4/12/22 05:52, Serge Semin wrote:
> On Mon, Apr 11, 2022 at 09:25:03PM +0900, Damien Le Moal wrote:
>> On 4/11/22 21:11, Serge Semin wrote:
>>> On Thu, Mar 24, 2022 at 11:05:58AM +0900, Damien Le Moal wrote:
>>>> On 3/24/22 09:16, Serge Semin wrote:
>>>>> Currently there are four port-map-related fields declared in the
>>>>> ahci_host_priv structure and used to setup the HBA ports mapping. First
>>>>> the ports-mapping is read from the PI register and immediately stored in
>>>>> the saved_port_map field. If forced_port_map is initialized with non-zero
>>>>> value then its value will have greater priority over the value read from
>>>>> PI, thus it will override the saved_port_map field. That value will be then
>>>>> masked by a non-zero mask_port_map field and after some sanity checks it
>>>>> will be stored in the ahci_host_priv.port_map field as a final port
>>>>> mapping.
>>>>>
>>>>> As you can see the logic is a bit too complicated for such a simple task.
>>>>> We can freely get rid from at least one of the fields with no change to
>>>>> the implemented semantic. The force_port_map field can be replaced with
>>>>> taking non-zero saved_port_map value into account. So if saved_port_map is
>>>>> pre-initialized by the glue-driver/platform-specific code then it will
>>>>
>>>
>>>> glue-driver == LLDD (low level device driver), for the entire series please.
>>>
>>> Why? It's a normal term and well known amongst developers. I've used it
>>> in a plenty of my patches before and none of them has been questioned in that
>>> part so far.
>>
> 
>> This term is not used in libata, nor do I remember seeing it used in SCSI
>> or block subsystem either. We always talk about mid-layer (ahci platform)
>> and LLDD (adapter driver).
> 
> Great, do we need to learn the subsystem-specific dictionary now
> before submitting the patches for it? =)
> Really, you are asking me to change one term to its synonym just
> because it's mainly unused here. Now you know what it means, the
> others can easily google it and get to learn something new. Win-win.)

I already knew what it meant, but it was unclear if my idea of what you
meant was actually the same as yours. Sticking with the vocabulary already
used since *a long time ago* makes life easier for reviewers and avoids
confusion.

-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter
  2022-04-11 22:48           ` Damien Le Moal
@ 2022-04-12 12:29             ` Serge Semin
  0 siblings, 0 replies; 65+ messages in thread
From: Serge Semin @ 2022-04-12 12:29 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Serge Semin, Hans de Goede, Jens Axboe, Alexey Malahov,
	Pavel Parkhomenko, Rob Herring, linux-ide, linux-kernel,
	devicetree

On Tue, Apr 12, 2022 at 07:48:50AM +0900, Damien Le Moal wrote:
> On 4/12/22 05:52, Serge Semin wrote:
> > On Mon, Apr 11, 2022 at 09:25:03PM +0900, Damien Le Moal wrote:
> >> On 4/11/22 21:11, Serge Semin wrote:
> >>> On Thu, Mar 24, 2022 at 11:05:58AM +0900, Damien Le Moal wrote:
> >>>> On 3/24/22 09:16, Serge Semin wrote:
> >>>>> Currently there are four port-map-related fields declared in the
> >>>>> ahci_host_priv structure and used to setup the HBA ports mapping. First
> >>>>> the ports-mapping is read from the PI register and immediately stored in
> >>>>> the saved_port_map field. If forced_port_map is initialized with non-zero
> >>>>> value then its value will have greater priority over the value read from
> >>>>> PI, thus it will override the saved_port_map field. That value will be then
> >>>>> masked by a non-zero mask_port_map field and after some sanity checks it
> >>>>> will be stored in the ahci_host_priv.port_map field as a final port
> >>>>> mapping.
> >>>>>
> >>>>> As you can see the logic is a bit too complicated for such a simple task.
> >>>>> We can freely get rid from at least one of the fields with no change to
> >>>>> the implemented semantic. The force_port_map field can be replaced with
> >>>>> taking non-zero saved_port_map value into account. So if saved_port_map is
> >>>>> pre-initialized by the glue-driver/platform-specific code then it will
> >>>>
> >>>
> >>>> glue-driver == LLDD (low level device driver), for the entire series please.
> >>>
> >>> Why? It's a normal term and well known amongst developers. I've used it
> >>> in a plenty of my patches before and none of them has been questioned in that
> >>> part so far.
> >>
> > 
> >> This term is not used in libata, nor do I remember seeing it used in SCSI
> >> or block subsystem either. We always talk about mid-layer (ahci platform)
> >> and LLDD (adapter driver).
> > 
> > Great, do we need to learn the subsystem-specific dictionary now
> > before submitting the patches for it? =)
> > Really, you are asking me to change one term to its synonym just
> > because it's mainly unused here. Now you know what it means, the
> > others can easily google it and get to learn something new. Win-win.)
> 

> I already knew what it meant, but it was unclear if my idea of what you
> meant was actually the same as yours. Sticking with the vocabulary already
> used since *a long time ago* makes life easier for reviewers and avoids
> confusion.

I believe there can't be too many possible meaning of that term to
have much doubts. Especially when we refer to the kernel drivers. One
more time requesting to settle some implicit subsystem-specific
conventions, not having them described in some kernel documents seems
very much wrong. The ahci_ prefixing and the specific vocabulary
concerns each driver in very many aspects. Seeing there are not a few
drivers which don't follow those conventions, you give no chance for
the developers to get their code accepted with no requests to fix the
corresponding parts. So to speak you need to thoroughly describe these
and the others conventions in the kernel documentation otherwise
you'll always end up requesting the same fixes wasting your and
developers time again and again.

Really if you had that document available, you could have used as a
reference and just said something like "please, follow the coding
style convention described here..." and no question would have raised.
Meanwhile currently both ahci_-prefix change and using the LLDD term
seem more like a personal desire to me.

-Sergey

> 
> -- 
> Damien Le Moal
> Western Digital Research

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

end of thread, other threads:[~2022-04-12 12:56 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
2022-03-29  8:15   ` Damien Le Moal
2022-04-11 19:25     ` Serge Semin
2022-03-24  0:16 ` [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema Serge Semin
2022-03-28 19:32   ` Rob Herring
2022-04-11 19:34     ` Serge Semin
2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
2022-03-24  0:58   ` Damien Le Moal
2022-03-24 21:37     ` Serge Semin
2022-03-25  1:56       ` Damien Le Moal
2022-04-06 20:03         ` Serge Semin
2022-03-29  8:20   ` Damien Le Moal
2022-03-24  0:16 ` [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods Serge Semin
2022-03-24  1:11   ` Damien Le Moal
2022-04-06 20:42     ` Serge Semin
2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
2022-03-24  1:29   ` Damien Le Moal
2022-04-09  4:59     ` Serge Semin
2022-03-28 22:36   ` kernel test robot
2022-03-28 23:42   ` kernel test robot
2022-03-29  0:03   ` kernel test robot
2022-03-24  0:16 ` [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id Serge Semin
2022-03-24  1:36   ` Damien Le Moal
2022-04-11  6:02     ` Serge Semin
2022-03-24  0:16 ` [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number Serge Semin
2022-03-24  1:40   ` Damien Le Moal
2022-03-24  8:12     ` Sergey Shtylyov
2022-03-24  8:13       ` Damien Le Moal
2022-04-11 13:10         ` Serge Semin
2022-03-24  0:16 ` [PATCH 08/21] ata: libahci_platform: Parse ports-implemented property in resources getter Serge Semin
2022-03-24  0:16   ` Serge Semin
2022-03-24  0:16   ` Serge Semin
2022-03-24  0:16 ` [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods Serge Semin
2022-03-24  1:52   ` Damien Le Moal
2022-04-11 10:57     ` Serge Semin
2022-03-24  0:16 ` [PATCH 10/21] dt-bindings: ata: ahci: Add platform capability properties Serge Semin
2022-03-24  0:16 ` [PATCH 11/21] ata: libahci: Extend port-cmd flags set with port capabilities Serge Semin
2022-03-24  0:16 ` [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter Serge Semin
2022-03-24  2:05   ` Damien Le Moal
2022-04-11 12:11     ` Serge Semin
2022-04-11 12:25       ` Damien Le Moal
2022-04-11 20:52         ` Serge Semin
2022-04-11 22:48           ` Damien Le Moal
2022-04-12 12:29             ` Serge Semin
2022-03-24  0:16 ` [PATCH 13/21] ata: libahci: Don't read AHCI version twice in the save-config method Serge Semin
2022-03-24  0:16 ` [PATCH 14/21] ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments Serge Semin
2022-03-24  0:16 ` [PATCH 15/21] ata: ahci: Introduce firmware-specific caps initialization Serge Semin
2022-03-24  0:16 ` [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema Serge Semin
2022-04-01  0:06   ` Rob Herring
2022-04-11 20:00     ` Serge Semin
2022-03-24  0:16 ` [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support Serge Semin
2022-03-24  2:21   ` Damien Le Moal
2022-04-11 12:41     ` Serge Semin
2022-04-11 13:03       ` Damien Le Moal
2022-04-11 20:41         ` Serge Semin
2022-03-24  0:16 ` [PATCH 18/21] dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema Serge Semin
2022-03-24  0:16 ` [PATCH 19/21] ata: ahci-dwc: Add platform-specific quirks support Serge Semin
2022-03-24  0:16 ` [PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support Serge Semin
2022-03-24  0:16 ` [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver Serge Semin
2022-03-24  2:17   ` Damien Le Moal
2022-04-11 12:16     ` Serge Semin
2022-03-28 20:06 ` [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Damien Le Moal
2022-03-29  8:30   ` Damien Le Moal
2022-04-06 19:54     ` Serge Semin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.