ata changes for 6.1-rc1

* Print the timeout value for internal command failures due to a
   timeout (from Tomas).
 
 * Improve parameter names in ata_dev_set_feature() to clarify this
   function use (from Niklas).
 
 * Improve the ahci driver low power mode setting initialization to allow
   more flexibility for the user (from Rafael).
 
 * Several patches to remove redundant variables in libata-core,
   libata-eh and the pata_macio driver and to fix typos in comments (from
   Jinpeng, Shaomin, Ye).
 
 * Some code simplifications and macro renaming (for clarity) in various
   functions of libata-core (from me).
 
 * Add a missing check for a potential failure of sata_scr_read() in
   sata_print_link_status() (from Li).
 
 * Cleanup of libata Kconfig PATA_PLATFORM and PATA_OF_PLATFORM options
   (from Lukas).
 
 * Cleanups of ata dt-bindings and improvements of libahci_platform, ahci
   and libahci code (from Serge)
 
 * New driver for Synopsys AHCI SATA controllers, based of the generic
   ahci code (from Serge). One compilation warning fix is added for this
   driver (from me).
 
 * Several fixes to macros used to discover a drive capabilities to be
   consistent with the ACS specifications (from Niklas).
 
 * A couple of simplifcations to some libata functions, removing
   unnecessary arguments (from Niklas).
 
 * An improvements to libata-eh code to avoid unnecessary link reset when
   revalidating a drive after a failed command. In practice, this extra,
   unneeded reset, reset does not cause any arm beyond slightly slowing
   down error recovery (from Niklas).
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCYz0asgAKCRDdoc3SxdoY
 drHoAQCJhb6MuQHzbN/wR5cTGAfWXQJWBJx2mJr7oKJCrB34PwD/RzphcsuaXDta
 kwbTGlpitegByZTDKt9eMRLWmKgyngw=
 =CnJj
 -----END PGP SIGNATURE-----

Merge tag 'ata-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata

Pull ata updates from Damien Le Moal:

 - Print the timeout value for internal command failures due to a
   timeout (from Tomas)

 - Improve parameter names in ata_dev_set_feature() to clarify this
   function use (from Niklas)

 - Improve the ahci driver low power mode setting initialization to
   allow more flexibility for the user (from Rafael)

 - Several patches to remove redundant variables in libata-core,
   libata-eh and the pata_macio driver and to fix typos in comments
   (from Jinpeng, Shaomin, Ye)

 - Some code simplifications and macro renaming (for clarity) in various
   functions of libata-core (from me)

 - Add a missing check for a potential failure of sata_scr_read() in
   sata_print_link_status() (from Li)

 - Cleanup of libata Kconfig PATA_PLATFORM and PATA_OF_PLATFORM options
   (from Lukas)

 - Cleanups of ata dt-bindings and improvements of libahci_platform,
   ahci and libahci code (from Serge)

 - New driver for Synopsys AHCI SATA controllers, based of the generic
   ahci code (from Serge). One compilation warning fix is added for this
   driver (from me)

 - Several fixes to macros used to discover a drive capabilities to be
   consistent with the ACS specifications (from Niklas)

 - A couple of simplifcations to some libata functions, removing
   unnecessary arguments (from Niklas)

 - An improvements to libata-eh code to avoid unnecessary link reset
   when revalidating a drive after a failed command. In practice, this
   extra, unneeded reset, reset does not cause any arm beyond slightly
   slowing down error recovery (from Niklas)

* tag 'ata-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata: (45 commits)
  ata: libata-eh: avoid needless hard reset when revalidating link
  ata: libata: drop superfluous ata_eh_analyze_tf() parameter
  ata: libata: drop superfluous ata_eh_request_sense() parameter
  ata: fix ata_id_has_dipm()
  ata: fix ata_id_has_ncq_autosense()
  ata: fix ata_id_has_devslp()
  ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
  ata: libata-eh: Remove the unneeded result variable
  ata: ahci_st: Enable compile test
  ata: ahci_st: Fix compilation warning
  MAINTAINERS: Add maintainers for DWC AHCI SATA driver
  ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support
  ata: ahci-dwc: Add platform-specific quirks support
  dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema
  ata: ahci: Add DWC AHCI SATA controller support
  ata: libahci_platform: Add function returning a clock-handle by id
  dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema
  ata: ahci: Introduce firmware-specific caps initialization
  ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments
  ata: libahci: Don't read AHCI version twice in the save-config method
  ...
This commit is contained in:
Linus Torvalds 2022-10-07 10:48:49 -07:00
commit 4078aa6850
33 changed files with 1332 additions and 288 deletions

View File

@ -0,0 +1,123 @@
# 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>
- Damien Le Moal <damien.lemoal@opensource.wdc.com>
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:
description: CSR space IDs
contains:
const: ahci
interrupts:
description:
Generic AHCI state change interrupt. Can be implemented either as a
single line attached to the controller or as a set of the signals
indicating the particular port events.
minItems: 1
maxItems: 32
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
hba-cap:
$ref: '/schemas/types.yaml#/definitions/uint32'
description:
Bitfield of the HBA generic platform capabilities like Staggered
Spin-up or Mechanical Presence Switch support. It can be used to
appropriately initialize the HWinit fields of the HBA CAP register
in case if the system firmware hasn't done it.
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-f]+$":
$ref: '#/$defs/ahci-port'
description:
It is optionally possible to describe the ports as sub-nodes so
to enable each port independently when dealing with multiple PHYs.
required:
- reg
- interrupts
additionalProperties: true
$defs:
ahci-port:
$ref: /schemas/ata/sata-common.yaml#/$defs/sata-port
properties:
reg:
description:
AHCI SATA port identifier. By design AHCI controller can't have
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:
description: AHCI SATA port PHY ID
const: sata-phy
target-supply:
description: Power regulator for SATA port target device
hba-port-cap:
$ref: '/schemas/types.yaml#/definitions/uint32'
description:
Bitfield of the HBA port-specific platform capabilities like Hot
plugging, eSATA, FIS-based Switching, etc (see AHCI specification
for details). It can be used to initialize the HWinit fields of
the PxCMD register in case if the system firmware hasn't done it.
required:
- reg
...

View File

@ -30,14 +30,11 @@ select:
- marvell,armada-3700-ahci
- marvell,armada-8k-ahci
- marvell,berlin2q-ahci
- snps,dwc-ahci
- snps,spear-ahci
required:
- compatible
allOf:
- $ref: "sata-common.yaml#"
- $ref: "ahci-common.yaml#"
properties:
compatible:
@ -49,17 +46,11 @@ properties:
- marvell,berlin2-ahci
- marvell,berlin2q-ahci
- const: generic-ahci
- items:
- enum:
- rockchip,rk3568-dwc-ahci
- const: snps,dwc-ahci
- enum:
- cavium,octeon-7130-ahci
- hisilicon,hisi-ahci
- ibm,476gtr-ahci
- marvell,armada-3700-ahci
- snps,dwc-ahci
- snps,spear-ahci
reg:
minItems: 1
@ -69,92 +60,37 @@ properties:
maxItems: 1
clocks:
description:
Clock IDs array as required by the controller.
minItems: 1
maxItems: 3
clock-names:
description:
Names of clocks corresponding to IDs in the clock property.
minItems: 1
maxItems: 3
interrupts:
maxItems: 1
ahci-supply:
description:
regulator for AHCI controller
dma-coherent: true
phy-supply:
description:
regulator for PHY power
phys:
description:
List of all PHYs on this controller
maxItems: 1
phy-names:
description:
Name specifier for the PHYs
maxItems: 1
ports-implemented:
$ref: '/schemas/types.yaml#/definitions/uint32'
description: |
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 SoCs.
maximum: 0x1f
power-domains:
maxItems: 1
resets:
maxItems: 1
target-supply:
description:
regulator for SATA target power
patternProperties:
"^sata-port@[0-9a-f]+$":
$ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port
anyOf:
- required: [ phys ]
- required: [ target-supply ]
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
patternProperties:
"^sata-port@[0-9a-f]+$":
type: object
additionalProperties: false
description:
Subnode with configuration of the Ports.
properties:
reg:
maxItems: 1
phys:
maxItems: 1
phy-names:
maxItems: 1
target-supply:
description:
regulator for SATA target power
required:
- reg
anyOf:
- required: [ phys ]
- required: [ target-supply ]
unevaluatedProperties: false
examples:
@ -167,6 +103,8 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/berlin2q.h>
#include <dt-bindings/ata/ahci.h>
sata@f7e90000 {
compatible = "marvell,berlin2q-ahci", "generic-ahci";
reg = <0xf7e90000 0x1000>;
@ -175,15 +113,23 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
hba-cap = <HBA_SMPS>;
sata0: sata-port@0 {
reg = <0>;
phys = <&sata_phy 0>;
target-supply = <&reg_sata0>;
hba-port-cap = <(HBA_PORT_FBSCP | HBA_PORT_ESP)>;
};
sata1: sata-port@1 {
reg = <1>;
phys = <&sata_phy 1>;
target-supply = <&reg_sata1>;
hba-port-cap = <(HBA_PORT_HPCP | HBA_PORT_MPSP | HBA_PORT_FBSCP)>;
};
};

View File

@ -0,0 +1,115 @@
# 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-common.yaml#
properties:
compatible:
const: baikal,bt1-ahci
clocks:
items:
- description: Peripheral APB bus clock
- description: Application AXI BIU clock
- description: SATA Ports reference clock
clock-names:
items:
- const: pclk
- const: aclk
- const: ref
resets:
items:
- description: Application AXI BIU domain reset
- description: SATA Ports clock domain reset
reset-names:
items:
- const: arst
- const: ref
ports-implemented:
maximum: 0x3
patternProperties:
"^sata-port@[0-1]$":
$ref: /schemas/ata/snps,dwc-ahci-common.yaml#/$defs/dwc-ahci-port
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]).
enum: [ 1, 2, 4, 8, 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]).
enum: [ 1, 2, 4, 8, 16 ]
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- resets
unevaluatedProperties: false
examples:
- |
sata@1f050000 {
compatible = "baikal,bt1-ahci";
reg = <0x1f050000 0x2000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 64 4>;
clocks = <&ccu_sys 1>, <&ccu_axi 2>, <&sata_ref_clk>;
clock-names = "pclk", "aclk", "ref";
resets = <&ccu_axi 2>, <&ccu_sys 0>;
reset-names = "arst", "ref";
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>;
};
};
...

View File

@ -14,7 +14,7 @@ maintainers:
- Florian Fainelli <f.fainelli@gmail.com>
allOf:
- $ref: sata-common.yaml#
- $ref: ahci-common.yaml#
properties:
compatible:
@ -41,8 +41,6 @@ properties:
interrupts:
maxItems: 1
dma-coherent: true
if:
properties:
compatible:

View File

@ -31,22 +31,27 @@ properties:
"#size-cells":
const: 0
dma-coherent: true
patternProperties:
"^sata-port@[0-9a-e]$":
$ref: '#/$defs/sata-port'
description: |
DT nodes for ports connected on the SATA host. The SATA port
nodes will be named "sata-port".
additionalProperties: true
$defs:
sata-port:
type: object
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.
additionalProperties: true
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 SATA port.
...

View File

@ -0,0 +1,102 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/ata/snps,dwc-ahci-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys DWC AHCI SATA controller properties
maintainers:
- Serge Semin <fancer.lancer@gmail.com>
description:
This document defines device tree schema for the generic Synopsys DWC
AHCI controller properties.
select: false
allOf:
- $ref: ahci-common.yaml#
properties:
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
description:
Basic DWC AHCI SATA clock sources like application AXI/AHB BIU clock,
PM-alive clock, RxOOB detection clock, embedded PHYs reference (Rx/Tx)
clock, etc.
minItems: 1
maxItems: 4
clock-names:
minItems: 1
maxItems: 4
items:
oneOf:
- description: Application APB/AHB/AXI BIU clock
enum:
- pclk
- aclk
- hclk
- sata
- description: Power Module keep-alive clock
const: pmalive
- description: RxOOB detection clock
const: rxoob
- description: SATA Ports reference clock
const: ref
resets:
description:
At least basic application and reference clock domains resets are
normally supported by the DWC AHCI SATA controller.
minItems: 1
maxItems: 4
reset-names:
minItems: 1
maxItems: 4
items:
oneOf:
- description: Application AHB/AXI BIU clock domain reset control
enum:
- arst
- hrst
- description: Power Module keep-alive clock domain reset control
const: pmalive
- description: RxOOB detection clock domain reset control
const: rxoob
- description: Reference clock domain reset control
const: ref
patternProperties:
"^sata-port@[0-9a-e]$":
$ref: '#/$defs/dwc-ahci-port'
additionalProperties: true
$defs:
dwc-ahci-port:
$ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port
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
enum: [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ]
snps,rx-ts-max:
$ref: /schemas/types.yaml#/definitions/uint32
description: Maximal size of Rx DMA transactions in FIFO words
enum: [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ]
...

View File

@ -0,0 +1,75 @@
# 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 generic Synopsys DWC
implementation of the AHCI SATA controller.
allOf:
- $ref: snps,dwc-ahci-common.yaml#
properties:
compatible:
oneOf:
- description: Synopsys AHCI SATA-compatible devices
const: snps,dwc-ahci
- description: SPEAr1340 AHCI SATA device
const: snps,spear-ahci
- description: Rockhip RK3568 AHCI controller
items:
- const: rockchip,rk3568-dwc-ahci
- const: snps,dwc-ahci
patternProperties:
"^sata-port@[0-9a-e]$":
$ref: /schemas/ata/snps,dwc-ahci-common.yaml#/$defs/dwc-ahci-port
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/ata/ahci.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-port-cap = <HBA_PORT_FBSCP>;
snps,tx-ts-max = <512>;
snps,rx-ts-max = <512>;
};
};
...

View File

@ -11584,6 +11584,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/dlemoal/libata.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

View File

@ -256,7 +256,6 @@ menuconfig ARCH_VEXPRESS
select GPIOLIB
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select HAVE_PATA_PLATFORM
select CLK_ICST
select NO_IOPORT_MAP
select PLAT_VERSATILE

View File

@ -195,7 +195,6 @@ config ARM64
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KVM
select HAVE_NMI
select HAVE_PATA_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP

View File

@ -176,9 +176,19 @@ config AHCI_DM816
If unsure, say N.
config AHCI_DWC
tristate "Synopsys DWC AHCI SATA support"
select SATA_HOST
select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
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
depends on ARCH_STI || COMPILE_TEST
select SATA_HOST
help
This option enables support for ST AHCI SATA controller.
@ -1102,8 +1112,7 @@ config PATA_PCMCIA
If unsure, say N.
config PATA_PLATFORM
tristate "Generic platform device PATA support"
depends on EXPERT || PPC || HAVE_PATA_PLATFORM
tristate "Generic platform device PATA support" if HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
@ -1112,7 +1121,8 @@ config PATA_PLATFORM
config PATA_OF_PLATFORM
tristate "OpenFirmware platform device PATA support"
depends on PATA_PLATFORM && OF
depends on OF
select PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems with OpenFirmware

View File

@ -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

View File

@ -657,7 +657,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;
}
/*
@ -690,7 +690,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);
@ -1609,15 +1609,12 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap,
goto update_policy;
}
#ifdef CONFIG_ACPI
if (policy > ATA_LPM_MED_POWER &&
(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
if (policy > ATA_LPM_MED_POWER && pm_suspend_default_s2idle()) {
if (hpriv->cap & HOST_CAP_PART)
policy = ATA_LPM_MIN_POWER_WITH_PARTIAL;
else if (hpriv->cap & HOST_CAP_SSC)
policy = ATA_LPM_MIN_POWER;
}
#endif
update_policy:
if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER)

View File

@ -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,
@ -139,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 */
@ -167,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 */
@ -182,6 +183,10 @@ 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 capabilities mask */
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 */
@ -323,7 +328,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 */
@ -334,12 +338,15 @@ 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 */
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 */
unsigned int f_rsts;
struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */
struct regulator *ahci_regulator;/* Optional */
@ -426,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);
@ -437,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)

View File

@ -163,7 +163,6 @@ static int ahci_da850_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
void __iomem *pwrdn_reg;
struct resource *res;
struct clk *clk;
u32 mpy;
int rc;
@ -172,36 +171,28 @@ static int ahci_da850_probe(struct platform_device *pdev)
return PTR_ERR(hpriv);
/*
* Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
* when trying to obtain the functional clock. This SATA controller
* uses two clocks for which we specify two connection ids. If we don't
* have the functional clock at this point - call clk_get() again with
* con_id = "fck".
* Internally ahci_platform_get_resources() calls the bulk clocks
* get method or falls back to using a single clk_get_optional().
* This AHCI SATA controller uses two clocks: functional clock
* with "fck" connection id and external reference clock with
* "refclk" id. If we haven't got all of them re-try the clocks
* getting procedure with the explicitly specified ids.
*/
if (!hpriv->clks[0]) {
clk = clk_get(dev, "fck");
if (IS_ERR(clk))
return PTR_ERR(clk);
if (hpriv->n_clks < 2) {
hpriv->clks = devm_kcalloc(dev, 2, sizeof(*hpriv->clks), GFP_KERNEL);
if (!hpriv->clks)
return -ENOMEM;
hpriv->clks[0] = clk;
hpriv->clks[0].id = "fck";
hpriv->clks[1].id = "refclk";
hpriv->n_clks = 2;
rc = devm_clk_bulk_get(dev, hpriv->n_clks, hpriv->clks);
if (rc)
return rc;
}
/*
* The second clock used by ahci-da850 is the external REFCLK. If we
* didn't get it from ahci_platform_get_resources(), let's try to
* specify the con_id in clk_get().
*/
if (!hpriv->clks[1]) {
clk = clk_get(dev, "refclk");
if (IS_ERR(clk)) {
dev_err(dev, "unable to obtain the reference clock");
return -ENODEV;
}
hpriv->clks[1] = clk;
}
mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1].clk));
if (mpy == 0) {
dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
return -EINVAL;

View File

@ -69,12 +69,12 @@ static int ahci_dm816_phy_init(struct ahci_host_priv *hpriv, struct device *dev)
* keep-alive clock and the external reference clock. We need the
* rate of the latter to calculate the correct value of MPY bits.
*/
if (!hpriv->clks[1]) {
if (hpriv->n_clks < 2) {
dev_err(dev, "reference clock not supplied\n");
return -EINVAL;
}
refclk_rate = clk_get_rate(hpriv->clks[1]);
refclk_rate = clk_get_rate(hpriv->clks[1].clk);
if ((refclk_rate % 100) != 0) {
dev_err(dev, "reference clock rate must be divisible by 100\n");
return -EINVAL;

493
drivers/ata/ahci_dwc.c Normal file
View File

@ -0,0 +1,493 @@
// 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/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"
#define DRV_NAME "ahci-dwc"
#define AHCI_DWC_FBS_PMPN_MAX 15
/* DWC AHCI SATA controller specific registers */
#define AHCI_DWC_HOST_OOBR 0xbc
#define AHCI_DWC_HOST_OOB_WE BIT(31)
#define AHCI_DWC_HOST_CWMIN_MASK GENMASK(30, 24)
#define AHCI_DWC_HOST_CWMAX_MASK GENMASK(23, 16)
#define AHCI_DWC_HOST_CIMIN_MASK GENMASK(15, 8)
#define AHCI_DWC_HOST_CIMAX_MASK GENMASK(7, 0)
#define AHCI_DWC_HOST_GPCR 0xd0
#define AHCI_DWC_HOST_GPSR 0xd4
#define AHCI_DWC_HOST_TIMER1MS 0xe0
#define AHCI_DWC_HOST_TIMV_MASK GENMASK(19, 0)
#define AHCI_DWC_HOST_GPARAM1R 0xe8
#define AHCI_DWC_HOST_ALIGN_M BIT(31)
#define AHCI_DWC_HOST_RX_BUFFER BIT(30)
#define AHCI_DWC_HOST_PHY_DATA_MASK GENMASK(29, 28)
#define AHCI_DWC_HOST_PHY_RST BIT(27)
#define AHCI_DWC_HOST_PHY_CTRL_MASK GENMASK(26, 21)
#define AHCI_DWC_HOST_PHY_STAT_MASK GENMASK(20, 15)
#define AHCI_DWC_HOST_LATCH_M BIT(14)
#define AHCI_DWC_HOST_PHY_TYPE_MASK GENMASK(13, 11)
#define AHCI_DWC_HOST_RET_ERR BIT(10)
#define AHCI_DWC_HOST_AHB_ENDIAN_MASK GENMASK(9, 8)
#define AHCI_DWC_HOST_S_HADDR BIT(7)
#define AHCI_DWC_HOST_M_HADDR BIT(6)
#define AHCI_DWC_HOST_S_HDATA_MASK GENMASK(5, 3)
#define AHCI_DWC_HOST_M_HDATA_MASK GENMASK(2, 0)
#define AHCI_DWC_HOST_GPARAM2R 0xec
#define AHCI_DWC_HOST_FBS_MEM_S BIT(19)
#define AHCI_DWC_HOST_FBS_PMPN_MASK GENMASK(17, 16)
#define AHCI_DWC_HOST_FBS_SUP BIT(15)
#define AHCI_DWC_HOST_DEV_CP BIT(14)
#define AHCI_DWC_HOST_DEV_MP BIT(13)
#define AHCI_DWC_HOST_ENCODE_M BIT(12)
#define AHCI_DWC_HOST_RXOOB_CLK_M BIT(11)
#define AHCI_DWC_HOST_RXOOB_M BIT(10)
#define AHCI_DWC_HOST_TXOOB_M BIT(9)
#define AHCI_DWC_HOST_RXOOB_M BIT(10)
#define AHCI_DWC_HOST_RXOOB_CLK_MASK GENMASK(8, 0)
#define AHCI_DWC_HOST_PPARAMR 0xf0
#define AHCI_DWC_HOST_TX_MEM_M BIT(11)
#define AHCI_DWC_HOST_TX_MEM_S BIT(10)
#define AHCI_DWC_HOST_RX_MEM_M BIT(9)
#define AHCI_DWC_HOST_RX_MEM_S BIT(8)
#define AHCI_DWC_HOST_TXFIFO_DEPTH GENMASK(7, 4)
#define AHCI_DWC_HOST_RXFIFO_DEPTH GENMASK(3, 0)
#define AHCI_DWC_HOST_TESTR 0xf4
#define AHCI_DWC_HOST_PSEL_MASK GENMASK(18, 16)
#define AHCI_DWC_HOST_TEST_IF BIT(0)
#define AHCI_DWC_HOST_VERSIONR 0xf8
#define AHCI_DWC_HOST_IDR 0xfc
#define AHCI_DWC_PORT_DMACR 0x70
#define AHCI_DWC_PORT_RXABL_MASK GENMASK(15, 12)
#define AHCI_DWC_PORT_TXABL_MASK GENMASK(11, 8)
#define AHCI_DWC_PORT_RXTS_MASK GENMASK(7, 4)
#define AHCI_DWC_PORT_TXTS_MASK GENMASK(3, 0)
#define AHCI_DWC_PORT_PHYCR 0x74
#define AHCI_DWC_PORT_PHYSR 0x78
/* Baikal-T1 AHCI SATA specific registers */
#define AHCI_BT1_HOST_PHYCR AHCI_DWC_HOST_GPCR
#define AHCI_BT1_HOST_MPLM_MASK GENMASK(29, 23)
#define AHCI_BT1_HOST_LOSDT_MASK GENMASK(22, 20)
#define AHCI_BT1_HOST_CRR BIT(19)
#define AHCI_BT1_HOST_CRW BIT(18)
#define AHCI_BT1_HOST_CRCD BIT(17)
#define AHCI_BT1_HOST_CRCA BIT(16)
#define AHCI_BT1_HOST_CRDI_MASK GENMASK(15, 0)
#define AHCI_BT1_HOST_PHYSR AHCI_DWC_HOST_GPSR
#define AHCI_BT1_HOST_CRA BIT(16)
#define AHCI_BT1_HOST_CRDO_MASK GENMASK(15, 0)
struct ahci_dwc_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 ahci_dwc_host_priv {
const struct ahci_dwc_plat_data *pdata;
struct platform_device *pdev;
u32 timv;
u32 dmacr[AHCI_MAX_PORTS];
};
static int ahci_bt1_init(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
int ret;
/* APB, application and reference clocks are required */
if (!ahci_platform_find_clk(hpriv, "pclk") ||
!ahci_platform_find_clk(hpriv, "aclk") ||
!ahci_platform_find_clk(hpriv, "ref")) {
dev_err(&dpriv->pdev->dev, "No system clocks specified\n");
return -EINVAL;
}
/*
* Fully reset the SATA AXI and ref clocks domain to ensure the state
* machine is working from scratch especially if the reference clocks
* source has been changed.
*/
ret = ahci_platform_assert_rsts(hpriv);
if (ret) {
dev_err(&dpriv->pdev->dev, "Couldn't assert the resets\n");
return ret;
}
ret = ahci_platform_deassert_rsts(hpriv);
if (ret) {
dev_err(&dpriv->pdev->dev, "Couldn't de-assert the resets\n");
return ret;
}
return 0;
}
static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)
{
struct ahci_dwc_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;
dpriv->pdata = device_get_match_data(&pdev->dev);
if (!dpriv->pdata)
return ERR_PTR(-EINVAL);
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;
}
static void ahci_dwc_check_cap(struct ahci_host_priv *hpriv)
{
unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
struct ahci_dwc_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 + AHCI_DWC_HOST_GPARAM2R);
dev_mp = !!(param & AHCI_DWC_HOST_DEV_MP);
dev_cp = !!(param & AHCI_DWC_HOST_DEV_CP);
fbs_sup = !!(param & AHCI_DWC_HOST_FBS_SUP);
fbs_pmp = 5 * FIELD_GET(AHCI_DWC_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 < AHCI_DWC_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 ahci_dwc_init_timer(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_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 + AHCI_DWC_HOST_TIMER1MS);
dpriv->timv = FIELD_GET(AHCI_DWC_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(AHCI_DWC_HOST_TIMV_MASK, rate);
writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
}
static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_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 + AHCI_DWC_PORT_DMACR);
if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
ts = ilog2(ts);
dmacr &= ~AHCI_DWC_PORT_TXTS_MASK;
dmacr |= FIELD_PREP(AHCI_DWC_PORT_TXTS_MASK, ts);
}
if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
ts = ilog2(ts);
dmacr &= ~AHCI_DWC_PORT_RXTS_MASK;
dmacr |= FIELD_PREP(AHCI_DWC_PORT_RXTS_MASK, ts);
}
writel(dmacr, port_mmio + AHCI_DWC_PORT_DMACR);
dpriv->dmacr[port] = dmacr;
}
return 0;
}
static int ahci_dwc_init_host(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_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;
}
ahci_dwc_check_cap(hpriv);
ahci_dwc_init_timer(hpriv);
rc = ahci_dwc_init_dmacr(hpriv);
if (rc)
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);
return rc;
}
static int ahci_dwc_reinit_host(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_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;
if (dpriv->pdata->reinit) {
rc = dpriv->pdata->reinit(hpriv);
if (rc)
goto err_disable_resources;
}
writel(dpriv->timv, hpriv->mmio + AHCI_DWC_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 + AHCI_DWC_PORT_DMACR);
}
return 0;
err_disable_resources:
ahci_platform_disable_resources(hpriv);
return rc;
}
static void ahci_dwc_clear_host(struct ahci_host_priv *hpriv)
{
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
if (dpriv->pdata->clear)
dpriv->pdata->clear(hpriv);
ahci_platform_disable_resources(hpriv);
}
static void ahci_dwc_stop_host(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
ahci_dwc_clear_host(hpriv);
}
static struct ata_port_operations ahci_dwc_port_ops = {
.inherits = &ahci_platform_ops,
.host_stop = ahci_dwc_stop_host,
};
static const struct ata_port_info ahci_dwc_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_dwc_port_ops,
};
static struct scsi_host_template ahci_dwc_scsi_info = {
AHCI_SHT(DRV_NAME),
};
static int ahci_dwc_probe(struct platform_device *pdev)
{
struct ahci_host_priv *hpriv;
int rc;
hpriv = ahci_dwc_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
rc = ahci_dwc_init_host(hpriv);
if (rc)
return rc;
rc = ahci_platform_init_host(pdev, hpriv, &ahci_dwc_port_info,
&ahci_dwc_scsi_info);
if (rc)
goto err_clear_host;
return 0;
err_clear_host:
ahci_dwc_clear_host(hpriv);
return rc;
}
static int ahci_dwc_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;
ahci_dwc_clear_host(hpriv);
return 0;
}
static int ahci_dwc_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
int rc;
rc = ahci_dwc_reinit_host(hpriv);
if (rc)
return rc;
return ahci_platform_resume_host(dev);
}
static DEFINE_SIMPLE_DEV_PM_OPS(ahci_dwc_pm_ops, ahci_dwc_suspend,
ahci_dwc_resume);
static struct ahci_dwc_plat_data ahci_dwc_plat = {
.pflags = AHCI_PLATFORM_GET_RESETS,
};
static struct ahci_dwc_plat_data ahci_bt1_plat = {
.pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER,
.init = ahci_bt1_init,
};
static const struct of_device_id ahci_dwc_of_match[] = {
{ .compatible = "snps,dwc-ahci", &ahci_dwc_plat },
{ .compatible = "snps,spear-ahci", &ahci_dwc_plat },
{ .compatible = "baikal,bt1-ahci", &ahci_bt1_plat },
{},
};
MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);
static struct platform_driver ahci_dwc_driver = {
.probe = ahci_dwc_probe,
.remove = ata_platform_remove_one,
.shutdown = ahci_platform_shutdown,
.driver = {
.name = DRV_NAME,
.of_match_table = ahci_dwc_of_match,
.pm = &ahci_dwc_pm_ops,
},
};
module_platform_driver(ahci_dwc_driver);
MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
MODULE_LICENSE("GPL");

View File

@ -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;
}

View File

@ -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;
@ -83,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", },
{ /* sentinel */ }

View File

@ -144,7 +144,6 @@ static struct scsi_host_template ahci_platform_sht = {
static int st_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct st_ahci_drv_data *drv_data;
struct ahci_host_priv *hpriv;
int err;
@ -168,9 +167,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) {

View File

@ -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,17 +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.
*/
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
/*
* Override HW-init HBA capability fields with the platform-specific
* values. The rest of the HBA capabilities are defined as Read-only
* and can't be modified in CSR anyway.
*/
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);
@ -517,15 +529,18 @@ 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) {
dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
port_map, 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%lx -> 0x%x\n",
port_map, hpriv->saved_port_map);
port_map = hpriv->saved_port_map;
} else {
hpriv->saved_port_map = port_map;
}
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;
@ -544,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;
}
@ -553,16 +568,30 @@ 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;
hpriv->version = readl(mmio + HOST_VERSION);
hpriv->version = vers;
hpriv->port_map = port_map;
if (!hpriv->start_engine)
@ -588,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)

View File

@ -93,32 +93,42 @@ 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 a pointer to the clock descriptor of the clock with
* the 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)
{
int i;
for (i = 0; i < hpriv->n_clks; i++) {
if (!strcmp(hpriv->clks[i].id, con_id))
return hpriv->clks[i].clk;
}
return NULL;
}
EXPORT_SYMBOL_GPL(ahci_platform_find_clk);
/**
* 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,19 +136,54 @@ 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);
/**
* ahci_platform_deassert_rsts - Deassert/trigger platform resets
* @hpriv: host private area to store config values
*
* This function deasserts or triggers all the reset lines 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.
*
* RETURNS:
* 0 on success otherwise a negative error code
*/
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);
/**
* ahci_platform_enable_regulators - Enable regulators
* @hpriv: host private area to store config values
@ -236,18 +281,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);
@ -274,7 +319,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);
@ -292,8 +337,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
@ -363,6 +406,34 @@ 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;
if (!of_property_read_u32(dev->of_node, "hba-cap", &hpriv->saved_cap))
hpriv->saved_cap &= (HOST_CAP_SSS | HOST_CAP_MPS);
of_property_read_u32(dev->of_node,
"ports-implemented", &hpriv->saved_port_map);
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_u32(child, "hba-port-cap", &hpriv->saved_port_cap[port]))
hpriv->saved_port_cap[port] &= PORT_CMD_CAP;
}
return 0;
}
/**
* ahci_platform_get_resources - Get platform resources
* @pdev: platform device to get resources for
@ -374,8 +445,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 +456,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 child_nodes, rc = -ENOMEM, enabled_ports = 0;
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct clk *clk;
struct device_node *child;
int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
u32 mask_port_map = 0;
if (!devres_open_group(dev, NULL, GFP_KERNEL))
@ -402,32 +472,51 @@ 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));
/*
* 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;
}
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);
/*
* Bulk clocks getting procedure can fail to find any clock due to
* running on a non-OF platform or due to the clocks being defined in
* bypass of 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)
goto err_out;
if (IS_ERR(clk)) {
rc = PTR_ERR(clk);
if (rc == -EPROBE_DEFER)
goto err_out;
break;
if (rc > 0) {
/* 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);
if (!hpriv->clks) {
rc = -ENOMEM;
goto err_out;
}
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 = "ahci";
hpriv->n_clks = 1;
}
hpriv->clks[i] = clk;
}
hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
@ -449,16 +538,28 @@ 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;
}
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
/*
* Too many sub-nodes most likely means having something wrong with
* the firmware.
*/
child_nodes = of_get_child_count(dev->of_node);
if (child_nodes > AHCI_MAX_PORTS) {
rc = -EINVAL;
goto err_out;
}
/*
* 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)
if (child_nodes)
hpriv->nports = child_nodes;
else
hpriv->nports = 1;
hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
@ -540,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;

View File

@ -665,33 +665,33 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
/**
* ata_build_rw_tf - Build ATA taskfile for given read/write request
* @tf: Target ATA taskfile
* @dev: ATA device @tf belongs to
* @qc: Metadata associated with the taskfile to build
* @block: Block address
* @n_block: Number of blocks
* @tf_flags: RW/FUA etc...
* @tag: tag
* @class: IO priority class
*
* LOCKING:
* None.
*
* Build ATA taskfile @tf for read/write request described by
* @block, @n_block, @tf_flags and @tag on @dev.
* Build ATA taskfile for the command @qc for read/write request described
* by @block, @n_block, @tf_flags and @class.
*
* RETURNS:
*
* 0 on success, -ERANGE if the request is too large for @dev,
* -EINVAL if the request is invalid.
*/
int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag, int class)
int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
unsigned int tf_flags, int class)
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->flags |= tf_flags;
if (ata_ncq_enabled(dev) && !ata_tag_internal(tag)) {
if (ata_ncq_enabled(dev)) {
/* yay, NCQ */
if (!lba_48_ok(block, n_block))
return -ERANGE;
@ -704,7 +704,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
else
tf->command = ATA_CMD_FPDMA_READ;
tf->nsect = tag << 3;
tf->nsect = qc->hw_tag << 3;
tf->hob_feature = (n_block >> 8) & 0xff;
tf->feature = n_block & 0xff;
@ -719,7 +719,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
if (tf->flags & ATA_TFLAG_FUA)
tf->device |= 1 << 7;
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE &&
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
class == IOPRIO_CLASS_RT)
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
} else if (dev->flags & ATA_DFLAG_LBA) {
@ -1578,8 +1578,8 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev,
else
ata_qc_complete(qc);
ata_dev_warn(dev, "qc timeout (cmd 0x%x)\n",
command);
ata_dev_warn(dev, "qc timeout after %u msecs (cmd 0x%x)\n",
timeout, command);
}
spin_unlock_irqrestore(ap->lock, flags);
@ -2171,7 +2171,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
return;
not_supported:
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
dev->flags &= ~ATA_DFLAG_NCQ_PRIO;
}
@ -3021,7 +3021,8 @@ static void sata_print_link_status(struct ata_link *link)
if (sata_scr_read(link, SCR_STATUS, &sstatus))
return;
sata_scr_read(link, SCR_CONTROL, &scontrol);
if (sata_scr_read(link, SCR_CONTROL, &scontrol))
return;
if (ata_phys_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
@ -4299,7 +4300,6 @@ static void ata_dev_xfermask(struct ata_device *dev)
static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
{
struct ata_taskfile tf;
unsigned int err_mask;
/* set up set-features taskfile */
ata_dev_dbg(dev, "set features - xfer mode\n");
@ -4321,20 +4321,20 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
else /* In the ancient relic department - skip all of this */
return 0;
/* On some disks, this command causes spin-up, so we need longer timeout */
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
return err_mask;
/*
* On some disks, this command causes spin-up, so we need longer
* timeout.
*/
return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
}
/**
* ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
* ata_dev_set_feature - Issue SET FEATURES
* @dev: Device to which command will be sent
* @enable: Whether to enable or disable the feature
* @feature: The sector count represents the feature to set
* @subcmd: The SET FEATURES subcommand to be sent
* @action: The sector count represents a subcommand specific action
*
* Issue SET FEATURES - SATA FEATURES command to device @dev
* on port @ap with sector count
* Issue SET FEATURES command to device @dev on port @ap with sector count
*
* LOCKING:
* PCI/etc. bus probe sem.
@ -4342,28 +4342,26 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
unsigned int ata_dev_set_feature(struct ata_device *dev, u8 subcmd, u8 action)
{
struct ata_taskfile tf;
unsigned int err_mask;
unsigned int timeout = 0;
/* set up set-features taskfile */
ata_dev_dbg(dev, "set features - SATA features\n");
ata_dev_dbg(dev, "set features\n");
ata_tf_init(dev, &tf);
tf.command = ATA_CMD_SET_FEATURES;
tf.feature = enable;
tf.feature = subcmd;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
tf.nsect = feature;
tf.nsect = action;
if (enable == SETFEATURES_SPINUP)
if (subcmd == SETFEATURES_SPINUP)
timeout = ata_probe_timeout ?
ata_probe_timeout * 1000 : SETFEATURES_SPINUP_TIMEOUT;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, timeout);
return err_mask;
return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, timeout);
}
EXPORT_SYMBOL_GPL(ata_dev_set_feature);

View File

@ -151,6 +151,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
#undef CMDS
static void __ata_port_freeze(struct ata_port *ap);
static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
struct ata_device **r_failed_dev);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@ -1086,14 +1088,11 @@ static void __ata_port_freeze(struct ata_port *ap)
*/
int ata_port_freeze(struct ata_port *ap)
{
int nr_aborted;
WARN_ON(!ap->ops->error_handler);
__ata_port_freeze(ap);
nr_aborted = ata_port_abort(ap);
return nr_aborted;
return ata_port_abort(ap);
}
EXPORT_SYMBOL_GPL(ata_port_freeze);
@ -1393,7 +1392,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
/**
* ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
* @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
* @cmd: scsi command for which the sense code should be set
*
* Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
* SENSE. This function is an EH helper.
@ -1401,9 +1399,9 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
* LOCKING:
* Kernel thread context (may sleep).
*/
static void ata_eh_request_sense(struct ata_queued_cmd *qc,
struct scsi_cmnd *cmd)
static void ata_eh_request_sense(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *cmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
struct ata_taskfile tf;
unsigned int err_mask;
@ -1541,7 +1539,6 @@ static void ata_eh_analyze_serror(struct ata_link *link)
/**
* ata_eh_analyze_tf - analyze taskfile of a failed qc
* @qc: qc to analyze
* @tf: Taskfile registers to analyze
*
* Analyze taskfile of @qc and further determine cause of
* failure. This function also requests ATAPI sense data if
@ -1553,9 +1550,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* RETURNS:
* Determined recovery action
*/
static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
const struct ata_taskfile *tf)
static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
{
const struct ata_taskfile *tf = &qc->result_tf;
unsigned int tmp, action = 0;
u8 stat = tf->status, err = tf->error;
@ -1579,7 +1576,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
switch (qc->dev->class) {
case ATA_DEV_ZAC:
if (stat & ATA_SENSE)
ata_eh_request_sense(qc, qc->scsicmd);
ata_eh_request_sense(qc);
fallthrough;
case ATA_DEV_ATA:
if (err & ATA_ICRC)
@ -1957,7 +1954,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask |= ehc->i.err_mask;
/* analyze TF */
ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
ehc->i.action |= ata_eh_analyze_tf(qc);
/* DEV errors are probably spurious in case of ATA_BUS error */
if (qc->err_mask & AC_ERR_ATA_BUS)
@ -2940,6 +2937,23 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
WARN_ON(dev->class == ATA_DEV_PMP);
/*
* The link may be in a deep sleep, wake it up.
*
* If the link is in deep sleep, ata_phys_link_offline()
* will return true, causing the revalidation to fail,
* which leads to a (potentially) needless hard reset.
*
* ata_eh_recover() will later restore the link policy
* to ap->target_lpm_policy after revalidation is done.
*/
if (link->lpm_policy > ATA_LPM_MAX_POWER) {
rc = ata_eh_set_lpm(link, ATA_LPM_MAX_POWER,
r_failed_dev);
if (rc)
goto err;
}
if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
rc = -EIO;
goto err;

View File

@ -870,7 +870,7 @@ static ssize_t ata_ncq_prio_enable_show(struct device *device,
if (!dev)
rc = -ENODEV;
else
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE;
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
spin_unlock_irq(ap->lock);
return rc ? rc : sysfs_emit(buf, "%u\n", ncq_prio_enable);
@ -905,9 +905,9 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
}
if (input)
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLE;
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED;
else
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
unlock:
spin_unlock_irq(ap->lock);

View File

@ -1603,9 +1603,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
qc->flags |= ATA_QCFLAG_IO;
qc->nbytes = n_block * scmd->device->sector_size;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->hw_tag, class);
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class);
if (likely(rc == 0))
return 0;

View File

@ -776,7 +776,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
* @qc: Command on going
* @bytes: number of bytes
*
* Transfer Transfer data from/to the ATAPI device.
* Transfer data from/to the ATAPI device.
*
* LOCKING:
* Inherited from caller.

View File

@ -44,9 +44,8 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
#endif
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag, int class);
extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
unsigned int tf_flags, int class);
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
struct ata_device *dev);
extern unsigned ata_exec_internal(struct ata_device *dev,
@ -64,7 +63,7 @@ extern int ata_dev_configure(struct ata_device *dev);
extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
extern unsigned int ata_dev_set_feature(struct ata_device *dev,
u8 enable, u8 feature);
u8 subcmd, u8 action);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);

View File

@ -666,8 +666,7 @@ static u8 pata_macio_bmdma_status(struct ata_port *ap)
* a multi-block transfer.
*
* - The dbdma fifo hasn't yet finished flushing to
* to system memory when the disk interrupt occurs.
*
* system memory when the disk interrupt occurs.
*/
/* First check for errors */

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause */
/*
* This header provides constants for most AHCI bindings.
*/
#ifndef _DT_BINDINGS_ATA_AHCI_H
#define _DT_BINDINGS_ATA_AHCI_H
/* Host Bus Adapter generic platform capabilities */
#define HBA_SSS (1 << 27)
#define HBA_SMPS (1 << 28)
/* Host Bus Adapter port-specific platform capabilities */
#define HBA_PORT_HPCP (1 << 18)
#define HBA_PORT_MPSP (1 << 19)
#define HBA_PORT_CPD (1 << 20)
#define HBA_PORT_ESP (1 << 21)
#define HBA_PORT_FBSCP (1 << 22)
#endif

View File

@ -13,6 +13,7 @@
#include <linux/compiler.h>
struct clk;
struct device;
struct ata_port_info;
struct ahci_host_priv;
@ -21,8 +22,12 @@ 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_deassert_rsts(struct ahci_host_priv *hpriv);
int 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);
@ -41,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 */

View File

@ -566,6 +566,18 @@ struct ata_bmdma_prd {
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 2)))
#define ata_id_has_devslp(id) \
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)))
#define ata_id_has_ncq_autosense(id) \
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 7)))
#define ata_id_has_dipm(id) \
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 3)))
#define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10))
#define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11))
#define ata_id_u32(id,n) \
@ -578,9 +590,6 @@ struct ata_bmdma_prd {
#define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
#define ata_id_has_ncq_autosense(id) \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
static inline bool ata_id_has_hipm(const u16 *id)
{
@ -592,17 +601,6 @@ static inline bool ata_id_has_hipm(const u16 *id)
return val & (1 << 9);
}
static inline bool ata_id_has_dipm(const u16 *id)
{
u16 val = id[ATA_ID_FEATURE_SUPP];
if (val == 0 || val == 0xffff)
return false;
return val & (1 << 3);
}
static inline bool ata_id_has_fua(const u16 *id)
{
if ((id[ATA_ID_CFSSE] & 0xC000) != 0x4000)
@ -771,16 +769,21 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
static inline bool ata_id_has_sense_reporting(const u16 *id)
{
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
if (!(id[ATA_ID_CFS_ENABLE_2] & BIT(15)))
return false;
return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
if ((id[ATA_ID_COMMAND_SET_3] & (BIT(15) | BIT(14))) != BIT(14))
return false;
return id[ATA_ID_COMMAND_SET_3] & BIT(6);
}
static inline bool ata_id_sense_reporting_enabled(const u16 *id)
{
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
if (!ata_id_has_sense_reporting(id))
return false;
return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
/* ata_id_has_sense_reporting() == true, word 86 must have bit 15 set */
if ((id[ATA_ID_COMMAND_SET_4] & (BIT(15) | BIT(14))) != BIT(14))
return false;
return id[ATA_ID_COMMAND_SET_4] & BIT(6);
}
/**

View File

@ -101,7 +101,7 @@ enum {
ATA_DFLAG_UNLOCK_HPA = (1 << 18), /* unlock HPA */
ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */
ATA_DFLAG_NCQ_PRIO = (1 << 20), /* device supports NCQ priority */
ATA_DFLAG_NCQ_PRIO_ENABLE = (1 << 21), /* Priority cmds sent to dev */
ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 21), /* Priority cmds sent to dev */
ATA_DFLAG_INIT_MASK = (1 << 24) - 1,
ATA_DFLAG_DETACH = (1 << 24),