Commit 64e22b86 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

Pull libata updates from Tejun Heo:

 - a number of libata core changes to better support NCQ TRIM.

 - ahci now supports MSI-X in single IRQ mode to support a new
   controller which doesn't implement MSI or INTX.

 - ahci now supports edge-triggered IRQ mode to support a new controller
   which for some odd reason did edge-triggered IRQ.

 - the usual controller support additions and changes.

* 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (27 commits)
  libata: Do not blacklist Micron M500DC
  ata: ahci_mvebu: add suspend/resume support
  ahci, msix: Fix build error for !PCI_MSI
  ahci: Add support for Cavium's ThunderX host controller
  ahci: Add generic MSI-X support for single interrupts to SATA PCI driver
  libata: finally use __initconst in ata_parse_force_one()
  drivers: ata: add support for Ceva sata host controller
  devicetree:bindings: add devicetree bindings for ceva ahci
  ahci: added support for Freescale AHCI sata
  ahci: Store irq number in struct ahci_host_priv
  ahci: Move interrupt enablement code to a separate function
  Doc: libata: Fix spelling typo found in libata.xml
  ata:sata_nv - Change 1 to true for bool type variable.
  ata: add Broadcom AHCI SATA3 driver for STB chips
  Documentation: devicetree: add Broadcom SATA binding
  libata: Fix regression when the NCQ Send and Receive log page is absent
  ata: hpt366: fix constant cast warning
  ata: ahci_xgene: potential NULL dereference in probe
  ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller.
  libahci: Add support to handle HOST_IRQ_STAT as edge trigger latch.
  ...
parents 6597ac8a 243918be
...@@ -90,6 +90,17 @@ gscr ...@@ -90,6 +90,17 @@ gscr
130: SATA_PMP_GSCR_SII_GPIO 130: SATA_PMP_GSCR_SII_GPIO
Only valid if the device is a PM. Only valid if the device is a PM.
trim
Shows the DSM TRIM mode currently used by the device. Valid
values are:
unsupported: Drive does not support DSM TRIM
unqueued: Drive supports unqueued DSM TRIM only
queued: Drive supports queued DSM TRIM
forced_unqueued: Drive's queued DSM support is known to be
buggy and only unqueued TRIM commands
are sent
spdn_cnt spdn_cnt
Number of time libata decided to lower the speed of link due to errors. Number of time libata decided to lower the speed of link due to errors.
......
Binding for CEVA AHCI SATA Controller
Required properties:
- reg: Physical base address and size of the controller's register area.
- compatible: Compatibility string. Must be 'ceva,ahci-1v84'.
- clocks: Input clock specifier. Refer to common clock bindings.
- interrupts: Interrupt specifier. Refer to interrupt binding.
Optional properties:
- ceva,broken-gen2: limit to gen1 speed instead of gen2.
Examples:
ahci@fd0c0000 {
compatible = "ceva,ahci-1v84";
reg = <0xfd0c0000 0x200>;
interrupt-parent = <&gic>;
interrupts = <0 133 4>;
clocks = <&clkc SATA_CLK_ID>;
ceva,broken-gen2;
};
...@@ -16,6 +16,8 @@ Required properties: ...@@ -16,6 +16,8 @@ Required properties:
- "snps,dwc-ahci" - "snps,dwc-ahci"
- "snps,exynos5440-ahci" - "snps,exynos5440-ahci"
- "snps,spear-ahci" - "snps,spear-ahci"
- "fsl,qoriq-ahci" : for qoriq series socs which include ls1021, ls2085, etc.
- "fsl,<chip>-ahci" : chip could be ls1021, ls2085 etc.
- "generic-ahci" - "generic-ahci"
- interrupts : <interrupt mapping for SATA IRQ> - interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping> - reg : <registers mapping>
......
* Broadcom SATA3 AHCI Controller for STB
SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node.
Required properties:
- compatible : compatible list, may contain "brcm,bcm7445-ahci" and/or
"brcm,sata3-ahci"
- reg : register mappings for AHCI and SATA_TOP_CTRL
- reg-names : "ahci" and "top-ctrl"
- interrupts : interrupt mapping for SATA IRQ
Also see ahci-platform.txt.
Example:
sata@f045a000 {
compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
reg-names = "ahci", "top-ctrl";
interrupts = <0 30 0>;
#address-cells = <1>;
#size-cells = <0>;
sata0: sata-port@0 {
reg = <0>;
phys = <&sata_phy 0>;
};
sata1: sata-port@1 {
reg = <1>;
phys = <&sata_phy 1>;
};
};
...@@ -1791,6 +1791,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1791,6 +1791,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
* [no]ncq: Turn on or off NCQ. * [no]ncq: Turn on or off NCQ.
* [no]ncqtrim: Turn off queued DSM TRIM.
* nohrst, nosrst, norst: suppress hard, soft * nohrst, nosrst, norst: suppress hard, soft
and both resets. and both resets.
......
...@@ -98,6 +98,15 @@ config SATA_AHCI_PLATFORM ...@@ -98,6 +98,15 @@ config SATA_AHCI_PLATFORM
If unsure, say N. If unsure, say N.
config AHCI_BRCMSTB
tristate "Broadcom STB AHCI SATA support"
depends on ARCH_BRCMSTB
help
This option enables support for the AHCI SATA3 controller found on
STB SoC's.
If unsure, say N.
config AHCI_DA850 config AHCI_DA850
tristate "DaVinci DA850 AHCI SATA support" tristate "DaVinci DA850 AHCI SATA support"
depends on ARCH_DAVINCI_DA850 depends on ARCH_DAVINCI_DA850
...@@ -124,6 +133,15 @@ config AHCI_IMX ...@@ -124,6 +133,15 @@ config AHCI_IMX
If unsure, say N. If unsure, say N.
config AHCI_CEVA
tristate "CEVA AHCI SATA support"
depends on OF
help
This option enables support for the CEVA AHCI SATA.
It can be found on the Xilinx Zynq UltraScale+ MPSoC.
If unsure, say N.
config AHCI_MVEBU config AHCI_MVEBU
tristate "Marvell EBU AHCI SATA support" tristate "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU depends on ARCH_MVEBU
......
...@@ -10,6 +10,8 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o ...@@ -10,6 +10,8 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.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_DA850) += ahci_da850.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
......
...@@ -433,6 +433,8 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id ...@@ -433,6 +433,8 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) if (!hpriv)
return -ENOMEM; return -ENOMEM;
hpriv->irq = pdev->irq;
hpriv->flags |= (unsigned long)pi.private_data; hpriv->flags |= (unsigned long)pi.private_data;
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
...@@ -498,7 +500,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id ...@@ -498,7 +500,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
acard_ahci_pci_print_info(host); acard_ahci_pci_print_info(host);
pci_set_master(pdev); pci_set_master(pdev);
return ahci_host_activate(host, pdev->irq, &acard_ahci_sht); return ahci_host_activate(host, &acard_ahci_sht);
} }
module_pci_driver(acard_ahci_pci_driver); module_pci_driver(acard_ahci_pci_driver);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/msi.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
#include <linux/libata.h> #include <linux/libata.h>
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
enum { enum {
AHCI_PCI_BAR_STA2X11 = 0, AHCI_PCI_BAR_STA2X11 = 0,
AHCI_PCI_BAR_CAVIUM = 0,
AHCI_PCI_BAR_ENMOTUS = 2, AHCI_PCI_BAR_ENMOTUS = 2,
AHCI_PCI_BAR_STANDARD = 5, AHCI_PCI_BAR_STANDARD = 5,
}; };
...@@ -1288,17 +1290,60 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) ...@@ -1288,17 +1290,60 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{} {}
#endif #endif
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, /*
struct ahci_host_priv *hpriv) * ahci_init_msix() only implements single MSI-X support, not multiple
* MSI-X per-port interrupts. This is needed for host controllers that only
* have MSI-X support implemented, but no MSI or intx.
*/
static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{ {
int rc, nvec; int rc, nvec;
struct msix_entry entry = {};
/* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI) if (hpriv->flags & AHCI_HFLAG_NO_MSI)
goto intx; return -ENODEV;
nvec = pci_msix_vec_count(pdev);
if (nvec < 0)
return nvec;
if (!nvec) {
rc = -ENODEV;
goto fail;
}
/*
* There can be more than one vector (e.g. for error detection or
* hdd hotplug). Only the first vector (entry.entry = 0) is used.
*/
rc = pci_enable_msix_exact(pdev, &entry, 1);
if (rc < 0)
goto fail;
hpriv->irq = entry.vector;
return 1;
fail:
dev_err(&pdev->dev,
"failed to enable MSI-X with error %d, # of vectors: %d\n",
rc, nvec);
return rc;
}
static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
int rc, nvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
return -ENODEV;
nvec = pci_msi_vec_count(pdev); nvec = pci_msi_vec_count(pdev);
if (nvec < 0) if (nvec < 0)
goto intx; return nvec;
/* /*
* If number of MSIs is less than number of ports then Sharing Last * If number of MSIs is less than number of ports then Sharing Last
...@@ -1311,8 +1356,8 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, ...@@ -1311,8 +1356,8 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
rc = pci_enable_msi_exact(pdev, nvec); rc = pci_enable_msi_exact(pdev, nvec);
if (rc == -ENOSPC) if (rc == -ENOSPC)
goto single_msi; goto single_msi;
else if (rc < 0) if (rc < 0)
goto intx; return rc;
/* fallback to single MSI mode if the controller enforced MRSM mode */ /* fallback to single MSI mode if the controller enforced MRSM mode */
if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
...@@ -1324,15 +1369,42 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, ...@@ -1324,15 +1369,42 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
if (nvec > 1) if (nvec > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI; hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
return nvec; goto out;
single_msi: single_msi:
if (pci_enable_msi(pdev)) nvec = 1;
goto intx;
return 1; rc = pci_enable_msi(pdev);
if (rc < 0)
return rc;
out:
hpriv->irq = pdev->irq;
return nvec;
}
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
int nvec;
nvec = ahci_init_msi(pdev, n_ports, hpriv);
if (nvec >= 0)
return nvec;
/*
* Currently, MSI-X support only implements single IRQ mode and
* exists for controllers which can't do other types of IRQ. Only
* set it up if MSI fails.
*/
nvec = ahci_init_msix(pdev, n_ports, hpriv);
if (nvec >= 0)
return nvec;
intx: /* lagacy intx interrupts */
pci_intx(pdev, 1); pci_intx(pdev, 1);
hpriv->irq = pdev->irq;
return 0; return 0;
} }
...@@ -1371,11 +1443,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1371,11 +1443,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev, dev_info(&pdev->dev,
"PDC42819 can only drive SATA devices with this driver\n"); "PDC42819 can only drive SATA devices with this driver\n");
/* Both Connext and Enmotus devices use non-standard BARs */ /* Some devices use non-standard BARs */
if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
ahci_pci_bar = AHCI_PCI_BAR_STA2X11; ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
else if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
/* /*
* The JMicron chip 361/363 contains one SATA controller and one * The JMicron chip 361/363 contains one SATA controller and one
...@@ -1497,13 +1571,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1497,13 +1571,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/ */
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
ahci_init_interrupts(pdev, n_ports, hpriv);
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;
host->private_data = hpriv; host->private_data = hpriv;
ahci_init_interrupts(pdev, n_ports, hpriv);
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN; host->flags |= ATA_HOST_PARALLEL_SCAN;
else else
...@@ -1549,7 +1623,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1549,7 +1623,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev); pci_set_master(pdev);
return ahci_host_activate(host, pdev->irq, &ahci_sht); return ahci_host_activate(host, &ahci_sht);
} }
module_pci_driver(ahci_pci_driver); module_pci_driver(ahci_pci_driver);
......
...@@ -238,6 +238,8 @@ enum { ...@@ -238,6 +238,8 @@ enum {
AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
Edge Triggered */
/* ap->flags bits */ /* ap->flags bits */
...@@ -341,6 +343,7 @@ struct ahci_host_priv { ...@@ -341,6 +343,7 @@ struct ahci_host_priv {
struct phy **phys; struct phy **phys;
unsigned nports; /* Number of ports */ unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */ void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
/* /*
* Optional ahci_start_engine override, if not set this gets set to the * Optional ahci_start_engine override, if not set this gets set to the
* default ahci_start_engine during ahci_save_initial_config, this can * default ahci_start_engine during ahci_save_initial_config, this can
...@@ -393,8 +396,7 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, ...@@ -393,8 +396,7 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
struct ata_port_info *pi); struct ata_port_info *pi);
int ahci_reset_em(struct ata_host *host); int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s); void ahci_print_info(struct ata_host *host, const char *scc_s);
int ahci_host_activate(struct ata_host *host, int irq, int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
struct scsi_host_template *sht);
void ahci_error_handler(struct ata_port *ap); void ahci_error_handler(struct ata_port *ap);
static inline void __iomem *__ahci_port_base(struct ata_host *host, static inline void __iomem *__ahci_port_base(struct ata_host *host,
......
/*
* Broadcom SATA3 AHCI Controller Driver
*
* Copyright © 2009-2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/ahci_platform.h>
#include <linux/compiler.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/libata.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include "ahci.h"
#define DRV_NAME "brcm-ahci"
#define SATA_TOP_CTRL_VERSION 0x0
#define SATA_TOP_CTRL_BUS_CTRL 0x4
#define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */
#define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */
#define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */
#define PIODATA_ENDIAN_SHIFT 6
#define ENDIAN_SWAP_NONE 0
#define ENDIAN_SWAP_FULL 2
#define OVERRIDE_HWINIT BIT(16)
#define SATA_TOP_CTRL_TP_CTRL 0x8
#define SATA_TOP_CTRL_PHY_CTRL 0xc
#define SATA_TOP_CTRL_PHY_CTRL_1 0x0
#define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14)
#define SATA_TOP_CTRL_PHY_CTRL_2 0x4
#define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0)
#define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1)
#define SATA_TOP_CTRL_2_SW_RST_RX BIT(2)
#define SATA_TOP_CTRL_2_SW_RST_TX BIT(3)
#define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
#define SATA_TOP_CTRL_PHY_OFFS 0x8
#define SATA_TOP_MAX_PHYS 2
#define SATA_TOP_CTRL_SATA_TP_OUT 0x1c
#define SATA_TOP_CTRL_CLIENT_INIT_CTRL 0x20
/* On big-endian MIPS, buses are reversed to big endian, so switch them back */
#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
#define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */
#define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */
#else
#define DATA_ENDIAN 0
#define MMIO_ENDIAN 0
#endif
#define BUS_CTRL_ENDIAN_CONF \
((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \
(DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
(MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
struct brcm_ahci_priv {
struct device *dev;
void __iomem *top_ctrl;
u32 port_mask;
};
static const struct ata_port_info ahci_brcm_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_platform_ops,
};
static inline u32 brcm_sata_readreg(void __iomem *addr)
{
/*
* MIPS endianness is configured by boot strap, which also reverses all
* bus endianness (i.e., big-endian CPU + big endian bus ==> native
* endian I/O).
*
* Other architectures (e.g., ARM) either do not support big endian, or
* else leave I/O in little endian mode.
*/
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
return __raw_readl(addr);
else
return readl_relaxed(addr);
}
static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
{
/* See brcm_sata_readreg() comments */
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
__raw_writel(val, addr);
else
writel_relaxed(val, addr);
}
static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
{
void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
(port * SATA_TOP_CTRL_PHY_OFFS);
void __iomem *p;
u32 reg;
/* clear PHY_DEFAULT_POWER_STATE */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
reg = brcm_sata_readreg(p);
reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
brcm_sata_writereg(reg, p);
/* reset the PHY digital logic */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
reg = brcm_sata_readreg(p);
reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
SATA_TOP_CTRL_2_SW_RST_RX);
reg |= SATA_TOP_CTRL_2_SW_RST_TX;
brcm_sata_writereg(reg, p);
reg = brcm_sata_readreg(p);
reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
brcm_sata_writereg(reg, p);
reg = brcm_sata_readreg(p);
reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
brcm_sata_writereg(reg, p);
(void)brcm_sata_readreg(p);
}
static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
{
void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
(port * SATA_TOP_CTRL_PHY_OFFS);
void __iomem *p;
u32 reg;
/* power-off the PHY digital logic */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
reg = brcm_sata_readreg(p);
reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
brcm_sata_writereg(reg, p);
/* set PHY_DEFAULT_POWER_STATE */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
reg = brcm_sata_readreg(p);
reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
brcm_sata_writereg(reg, p);
}
static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
{
int i;
for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
if (priv->port_mask & BIT(i))
brcm_sata_phy_enable(priv, i);
}
static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
{
int i;
for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
if (priv->port_mask & BIT(i))
brcm_sata_phy_disable(priv, i);
}
static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
struct brcm_ahci_priv *priv)
{
void __iomem *ahci;
struct resource *res;
u32 impl;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
ahci = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ahci))
return 0;
impl = readl(ahci + HOST_PORTS_IMPL);
if (fls(impl) > SATA_TOP_MAX_PHYS)
dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
impl);
else if (!impl)
dev_info(priv->dev, "no ports found\n");
devm_iounmap(&pdev->dev, ahci);
devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
return impl;
}
static void brcm_sata_init(struct brcm_ahci_priv *priv)
{
/* Configure endianness */
brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF,
priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
}
static int brcm_ahci_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
int ret;
ret = ahci_platform_suspend(dev);
brcm_sata_phys_disable(priv);
return ret;
}
static int brcm_ahci_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
brcm_sata_init(priv);
brcm_sata_phys_enable(priv);
return ahci_platform_resume(dev);
}
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
static int brcm_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct brcm_ahci_priv *priv;
struct ahci_host_priv *hpriv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
priv->top_ctrl = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->top_ctrl))
return PTR_ERR(priv->top_ctrl);
brcm_sata_init(priv);
priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
if (!priv->port_mask)
return -ENODEV;
brcm_sata_phys_enable(priv);
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
hpriv->plat_data = priv;
ret = ahci_platform_enable_resources(hpriv);
if (ret)
return ret;
ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
&ahci_platform_sht);
if (ret)
return ret;
dev_info(dev, "Broadcom AHCI SATA3 registered\n");
return 0;
}
static int brcm_ahci_remove(struct platform_device *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
int ret;
ret = ata_platform_remove_one(pdev);
if (ret)
return ret;
brcm_sata_phys_disable(priv);
return 0;
}
static const struct of_device_id ahci_of_match[] = {
{.compatible = "brcm,bcm7445-ahci"},
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
static struct platform_driver brcm_ahci_driver = {
.probe = brcm_ahci_probe,
.remove = brcm_ahci_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = ahci_of_match,
.pm = &ahci_brcm_pm_ops,
},
};
module_platform_driver(brcm_ahci_driver);
MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
MODULE_AUTHOR("Brian Norris");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:sata-brcmstb");
/*
* Copyright (C) 2015 Xilinx, Inc.
* CEVA AHCI SATA platform driver
*
* based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/ahci_platform.h>
#include <linux/kernel.h>
#include <linux/libata.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "ahci.h"
/* Vendor Specific Register Offsets */
#define AHCI_VEND_PCFG 0xA4
#define AHCI_VEND_PPCFG 0xA8
#define AHCI_VEND_PP2C 0xAC
#define AHCI_VEND_PP3C 0xB0
#define AHCI_VEND_PP4C 0xB4
#define AHCI_VEND_PP5C 0xB8
#define AHCI_VEND_PAXIC 0xC0
#define AHCI_VEND_PTC 0xC8
/* Vendor Specific Register bit definitions */
#define PAXIC_ADBW_BW64 0x1
#define PAXIC_MAWIDD (1 << 8)
#define PAXIC_MARIDD (1 << 16)
#define PAXIC_OTL (0x4 << 20)
#define PCFG_TPSS_VAL (0x32 << 16)
#define PCFG_TPRS_VAL (0x2 << 12)
#define PCFG_PAD_VAL 0x2
#define PPCFG_TTA 0x1FFFE
#define PPCFG_PSSO_EN (1 << 28)
#define PPCFG_PSS_EN (1 << 29)
#define PPCFG_ESDF_EN (1 << 31)
#define PP2C_CIBGMN 0x0F
#define PP2C_CIBGMX (0x25 << 8)
#define PP2C_CIBGN (0x18 << 16)
#define PP2C_CINMP (0x29 << 24)
#define PP3C_CWBGMN 0x04
#define PP3C_CWBGMX (0x0B << 8)
#define PP3C_CWBGN (0x08 << 16)
#define PP3C_CWNMP (0x0F << 24)
#define PP4C_BMX 0x0a
#define PP4C_BNM (0x08 << 8)
#define PP4C_SFD (0x4a << 16)
#define PP4C_PTST (0x06 << 24)
#define PP5C_RIT 0x60216
#define PP5C_RCT (0x7f0 << 20)
#define PTC_RX_WM_VAL 0x40
#define PTC_RSVD (1 << 27)
#define PORT0_BASE 0x100
#define PORT1_BASE 0x180
/* Port Control Register Bit Definitions */
#define PORT_SCTL_SPD_GEN2 (0x2 << 4)
#define PORT_SCTL_SPD_GEN1 (0x1 << 4)
#define PORT_SCTL_IPM (0x3 << 8)
#define PORT_BASE 0x100
#define PORT_OFFSET 0x80
#define NR_PORTS 2
#define DRV_NAME "ahci-ceva"
#define CEVA_FLAG_BROKEN_GEN2 1
struct ceva_ahci_priv {
struct platform_device *ahci_pdev;
int flags;
};
static struct ata_port_operations ahci_ceva_ops = {
.inherits = &ahci_platform_ops,
};
static const struct ata_port_info ahci_ceva_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ceva_ops,
};
static void ahci_ceva_setup(struct ahci_host_priv *hpriv)
{
void __iomem *mmio = hpriv->mmio;
struct ceva_ahci_priv *cevapriv = hpriv->plat_data;
u32 tmp;
int i;
/*
* AXI Data bus width to 64
* Set Mem Addr Read, Write ID for data transfers
* Transfer limit to 72 DWord
*/
tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL;
writel(tmp, mmio + AHCI_VEND_PAXIC);
/* Set AHCI Enable */
tmp = readl(mmio + HOST_CTL);
tmp |= HOST_AHCI_EN;
writel(tmp, mmio + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
/* TPSS TPRS scalars, CISE and Port Addr */
tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i);
writel(tmp, mmio + AHCI_VEND_PCFG);
/* Port Phy Cfg register enables */
tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN;
writel(tmp, mmio + AHCI_VEND_PPCFG);
/* Phy Control OOB timing parameters COMINIT */
tmp = PP2C_CIBGMN | PP2C_CIBGMX | PP2C_CIBGN | PP2C_CINMP;
writel(tmp, mmio + AHCI_VEND_PP2C);
/* Phy Control OOB timing parameters COMWAKE */
tmp = PP3C_CWBGMN | PP3C_CWBGMX | PP3C_CWBGN | PP3C_CWNMP;
writel(tmp, mmio + AHCI_VEND_PP3C);
/* Phy Control Burst timing setting */
tmp = PP4C_BMX | PP4C_BNM | PP4C_SFD | PP4C_PTST;
writel(tmp, mmio + AHCI_VEND_PP4C);
/* Rate Change Timer and Retry Interval Timer setting */
tmp = PP5C_RIT | PP5C_RCT;
writel(tmp, mmio + AHCI_VEND_PP5C);
/* Rx Watermark setting */
tmp = PTC_RX_WM_VAL | PTC_RSVD;
writel(tmp, mmio + AHCI_VEND_PTC);
/* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */
tmp = PORT_SCTL_SPD_GEN2 | PORT_SCTL_IPM;
if (cevapriv->flags & CEVA_FLAG_BROKEN_GEN2)
tmp = PORT_SCTL_SPD_GEN1 | PORT_SCTL_IPM;
writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i);
}
}
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
static int ceva_ahci_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct ceva_ahci_priv *cevapriv;
int rc;
cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL);
if (!cevapriv)
return -ENOMEM;
cevapriv->ahci_pdev = pdev;
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
rc = ahci_platform_enable_resources(hpriv);
if (rc)
return rc;
if (of_property_read_bool(np, "ceva,broken-gen2"))
cevapriv->flags = CEVA_FLAG_BROKEN_GEN2;
hpriv->plat_data = cevapriv;
/* CEVA specific initialization */
ahci_ceva_setup(hpriv);
rc = ahci_platform_init_host(pdev, hpriv, &ahci_ceva_port_info,
&ahci_platform_sht);
if (rc)
goto disable_resources;
return 0;
disable_resources:
ahci_platform_disable_resources(hpriv);
return rc;
}
static int __maybe_unused ceva_ahci_suspend(struct device *dev)
{
return ahci_platform_suspend_host(dev);
}
static int __maybe_unused ceva_ahci_resume(struct device *dev)
{
return ahci_platform_resume_host(dev);
}
static SIMPLE_DEV_PM_OPS(ahci_ceva_pm_ops, ceva_ahci_suspend, ceva_ahci_resume);
static const struct of_device_id ceva_ahci_of_match[] = {
{ .compatible = "ceva,ahci-1v84" },
{},
};
MODULE_DEVICE_TABLE(of, ceva_ahci_of_match);
static struct platform_driver ceva_ahci_driver = {
.probe = ceva_ahci_probe,
.remove = ata_platform_remove_one,
.driver = {
.name = DRV_NAME,
.of_match_table = ceva_ahci_of_match,
.pm = &ahci_ceva_pm_ops,
},
};
module_platform_driver(ceva_ahci_driver);
MODULE_DESCRIPTION("CEVA AHCI SATA platform driver");
MODULE_AUTHOR("Xilinx Inc.");
MODULE_LICENSE("GPL v2");
...@@ -62,6 +62,26 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) ...@@ -62,6 +62,26 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
} }
static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state)
{
return ahci_platform_suspend_host(&pdev->dev);
}
static int ahci_mvebu_resume(struct platform_device *pdev)
{
struct ata_host *host = platform_get_drvdata(pdev);
struct ahci_host_priv *hpriv = host->private_data;
const struct mbus_dram_target_info *dram;
dram = mv_mbus_dram_info();
if (dram)
ahci_mvebu_mbus_config(hpriv, dram);
ahci_mvebu_regret_option(hpriv);
return ahci_platform_resume_host(&pdev->dev);
}
static const struct ata_port_info ahci_mvebu_port_info = { static const struct ata_port_info ahci_mvebu_port_info = {
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
...@@ -120,6 +140,8 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); ...@@ -120,6 +140,8 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);
static struct platform_driver ahci_mvebu_driver = { static struct platform_driver ahci_mvebu_driver = {
.probe = ahci_mvebu_probe, .probe = ahci_mvebu_probe,
.remove = ata_platform_remove_one, .remove = ata_platform_remove_one,
.suspend = ahci_mvebu_suspend,
.resume = ahci_mvebu_resume,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = ahci_mvebu_of_match, .of_match_table = ahci_mvebu_of_match,
......
...@@ -74,6 +74,7 @@ static const struct of_device_id ahci_of_match[] = { ...@@ -74,6 +74,7 @@ static const struct of_device_id ahci_of_match[] = {
{ .compatible = "ibm,476gtr-ahci", }, { .compatible = "ibm,476gtr-ahci", },
{ .compatible = "snps,dwc-ahci", }, { .compatible = "snps,dwc-ahci", },
{ .compatible = "hisilicon,hisi-ahci", }, { .compatible = "hisilicon,hisi-ahci", },
{ .compatible = "fsl,qoriq-ahci", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ahci_of_match); MODULE_DEVICE_TABLE(of, ahci_of_match);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/ahci_platform.h> #include <linux/ahci_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include "ahci.h" #include "ahci.h"
...@@ -84,6 +85,11 @@ ...@@ -84,6 +85,11 @@
/* Max retry for link down */ /* Max retry for link down */
#define MAX_LINK_DOWN_RETRY 3 #define MAX_LINK_DOWN_RETRY 3
enum xgene_ahci_version {
XGENE_AHCI_V1 = 1,
XGENE_AHCI_V2,
};
struct xgene_ahci_context { struct xgene_ahci_context {
struct ahci_host_priv *hpriv; struct ahci_host_priv *hpriv;
struct device *dev; struct device *dev;
...@@ -542,7 +548,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, ...@@ -542,7 +548,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
return rc; return rc;
} }
static struct ata_port_operations xgene_ahci_ops = { static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops, .inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop, .host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset, .hardreset = xgene_ahci_hardreset,
...@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = { ...@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = {
.pmp_softreset = xgene_ahci_pmp_softreset .pmp_softreset = xgene_ahci_pmp_softreset
}; };
static const struct ata_port_info xgene_ahci_port_info = { static const struct ata_port_info xgene_ahci_v1_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &xgene_ahci_v1_ops,
};
static struct ata_port_operations xgene_ahci_v2_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset,
.read_id = xgene_ahci_read_id,
};
static const struct ata_port_info xgene_ahci_v2_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &xgene_ahci_ops, .port_ops = &xgene_ahci_v2_ops,
}; };
static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
...@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = { ...@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME), AHCI_SHT(DRV_NAME),
}; };
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_ahci_acpi_match[] = {
{ "APMC0D0D", XGENE_AHCI_V1},
{ "APMC0D32", XGENE_AHCI_V2},
{},
};
MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
#endif
static const struct of_device_id xgene_ahci_of_match[] = {
{.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1},
{.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2},
{},
};
MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
static int xgene_ahci_probe(struct platform_device *pdev) static int xgene_ahci_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv; struct ahci_host_priv *hpriv;
struct xgene_ahci_context *ctx; struct xgene_ahci_context *ctx;
struct resource *res; struct resource *res;
const struct of_device_id *of_devid;
enum xgene_ahci_version version = XGENE_AHCI_V1;
const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info,
&xgene_ahci_v2_port_info };
int rc; int rc;
hpriv = ahci_platform_get_resources(pdev); hpriv = ahci_platform_get_resources(pdev);
...@@ -677,6 +717,35 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -677,6 +717,35 @@ static int xgene_ahci_probe(struct platform_device *pdev)
ctx->csr_mux = csr; ctx->csr_mux = csr;
} }
of_devid = of_match_device(xgene_ahci_of_match, dev);
if (of_devid) {
if (of_devid->data)
version = (enum xgene_ahci_version) of_devid->data;
}
#ifdef CONFIG_ACPI
else {
const struct acpi_device_id *acpi_id;
struct acpi_device_info *info;
acpi_status status;
acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev);
if (!acpi_id) {
dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n");
version = XGENE_AHCI_V1;
} else if (acpi_id->driver_data) {
version = (enum xgene_ahci_version) acpi_id->driver_data;
status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info);
if (ACPI_FAILURE(status)) {
dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
__func__);
version = XGENE_AHCI_V1;
}
if (info->valid & ACPI_VALID_CID)
version = XGENE_AHCI_V2;
}
}
#endif
dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
hpriv->mmio); hpriv->mmio);
...@@ -704,9 +773,19 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -704,9 +773,19 @@ static int xgene_ahci_probe(struct platform_device *pdev)
/* Configure the host controller */ /* Configure the host controller */
xgene_ahci_hw_init(hpriv); xgene_ahci_hw_init(hpriv);
skip_clk_phy: skip_clk_phy:
hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, switch (version) {
case XGENE_AHCI_V1:
hpriv->flags = AHCI_HFLAG_NO_NCQ;
break;
case XGENE_AHCI_V2:
hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
break;
default:
break;
}
rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1],
&ahci_platform_sht); &ahci_platform_sht);
if (rc) if (rc)
goto disable_resources; goto disable_resources;
...@@ -719,20 +798,6 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -719,20 +798,6 @@ static int xgene_ahci_probe(struct platform_device *pdev)
return rc; return rc;
} }
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_ahci_acpi_match[] = {
{ "APMC0D0D", },
{ }
};
MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
#endif
static const struct of_device_id xgene_ahci_of_match[] = {
{.compatible = "apm,xgene-ahci"},
{},
};
MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
static struct platform_driver xgene_ahci_driver = { static struct platform_driver xgene_ahci_driver = {
.probe = xgene_ahci_probe, .probe = xgene_ahci_probe,
.remove = ata_platform_remove_one, .remove = ata_platform_remove_one,
......
...@@ -1825,11 +1825,38 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) ...@@ -1825,11 +1825,38 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
} }
static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
{
unsigned int i, handled = 0;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
if (!(irq_masked & (1 << i)))
continue;
ap = host->ports[i];
if (ap) {
ahci_port_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
if (ata_ratelimit())
dev_warn(host->dev,
"interrupt on disabled port %u\n", i);
}
handled = 1;
}
return handled;
}
static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
{ {
struct ata_host *host = dev_instance; struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv; struct ahci_host_priv *hpriv;
unsigned int i, handled = 0; unsigned int rc = 0;
void __iomem *mmio; void __iomem *mmio;
u32 irq_stat, irq_masked; u32 irq_stat, irq_masked;
...@@ -1847,25 +1874,44 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) ...@@ -1847,25 +1874,44 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
spin_lock(&host->lock); spin_lock(&host->lock);
for (i = 0; i < host->n_ports; i++) { /*
struct ata_port *ap; * HOST_IRQ_STAT behaves as edge triggered latch meaning that
* it should be cleared before all the port events are cleared.
*/
writel(irq_stat, mmio + HOST_IRQ_STAT);
if (!(irq_masked & (1 << i))) rc = ahci_handle_port_intr(host, irq_masked);
continue;
ap = host->ports[i]; spin_unlock(&host->lock);
if (ap) {
ahci_port_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
if (ata_ratelimit())
dev_warn(host->dev,
"interrupt on disabled port %u\n", i);
}
handled = 1; VPRINTK("EXIT\n");
}
return IRQ_RETVAL(rc);
}
static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv;
unsigned int rc = 0;
void __iomem *mmio;
u32 irq_stat, irq_masked;
VPRINTK("ENTER\n");
hpriv = host->private_data;
mmio = hpriv->mmio;
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
if (!irq_stat)
return IRQ_NONE;
irq_masked = irq_stat & hpriv->port_map;
spin_lock(&host->lock);
rc = ahci_handle_port_intr(host, irq_masked);
/* HOST_IRQ_STAT behaves as level triggered latch meaning that /* HOST_IRQ_STAT behaves as level triggered latch meaning that
* it should be cleared after all the port events are cleared; * it should be cleared after all the port events are cleared;
...@@ -1882,7 +1928,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) ...@@ -1882,7 +1928,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
VPRINTK("EXIT\n"); VPRINTK("EXIT\n");
return IRQ_RETVAL(handled); return IRQ_RETVAL(rc);
} }
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
...@@ -2297,7 +2343,7 @@ static int ahci_port_start(struct ata_port *ap) ...@@ -2297,7 +2343,7 @@ static int ahci_port_start(struct ata_port *ap)
/* /*
* Switch to per-port locking in case each port has its own MSI vector. * Switch to per-port locking in case each port has its own MSI vector.
*/ */
if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
spin_lock_init(&pp->lock); spin_lock_init(&pp->lock);
ap->lock = &pp->lock; ap->lock = &pp->lock;
} }
...@@ -2425,7 +2471,10 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, ...@@ -2425,7 +2471,10 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
rc = ata_host_start(host); rc = ata_host_start(host);
if (rc) if (rc)
return rc; return rc;
/*
* Requests IRQs according to AHCI-1.1 when multiple MSIs were
* allocated. That is one MSI per port, starting from @irq.
*/
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data; struct ahci_port_priv *pp = host->ports[i]->private_data;
...@@ -2464,29 +2513,27 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, ...@@ -2464,29 +2513,27 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
/** /**
* ahci_host_activate - start AHCI host, request IRQs and register it * ahci_host_activate - start AHCI host, request IRQs and register it
* @host: target ATA host * @host: target ATA host
* @irq: base IRQ number to request
* @sht: scsi_host_template to use when registering the host * @sht: scsi_host_template to use when registering the host
* *
* Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
* when multiple MSIs were allocated. That is one MSI per port, starting
* from @irq.
*
* LOCKING: * LOCKING:
* Inherited from calling layer (may sleep). * Inherited from calling layer (may sleep).
* *
* RETURNS: * RETURNS:
* 0 on success, -errno otherwise. * 0 on success, -errno otherwise.
*/ */
int ahci_host_activate(struct ata_host *host, int irq, int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
struct scsi_host_template *sht)
{ {
struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data;
int irq = hpriv->irq;
int rc; int rc;
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
rc = ahci_host_activate_multi_irqs(host, irq, sht); rc = ahci_host_activate_multi_irqs(host, irq, sht);
else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
IRQF_SHARED, sht);
else else
rc = ata_host_activate(host, irq, ahci_single_irq_intr, rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
IRQF_SHARED, sht); IRQF_SHARED, sht);
return rc; return rc;
} }
......
...@@ -518,6 +518,8 @@ int ahci_platform_init_host(struct platform_device *pdev, ...@@ -518,6 +518,8 @@ int ahci_platform_init_host(struct platform_device *pdev,
return -EINVAL; return -EINVAL;
} }
hpriv->irq = irq;
/* prepare host */ /* prepare host */
pi.private_data = (void *)(unsigned long)hpriv->flags; pi.private_data = (void *)(unsigned long)hpriv->flags;
...@@ -588,7 +590,7 @@ int ahci_platform_init_host(struct platform_device *pdev, ...@@ -588,7 +590,7 @@ int ahci_platform_init_host(struct platform_device *pdev,
ahci_init_controller(host); ahci_init_controller(host);
ahci_print_info(host, "platform"); ahci_print_info(host, "platform");
return ahci_host_activate(host, irq, sht); return ahci_host_activate(host, sht);
} }
EXPORT_SYMBOL_GPL(ahci_platform_init_host); EXPORT_SYMBOL_GPL(ahci_platform_init_host);
......
...@@ -3654,7 +3654,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, ...@@ -3654,7 +3654,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* EH context. * EH context.
* *
* RETURNS: * RETURNS:
* 0 on succes, -errno otherwise. * 0 on success, -errno otherwise.
*/ */
int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
bool spm_wakeup) bool spm_wakeup)
...@@ -4225,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ...@@ -4225,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
/* devices that don't properly handle queued TRIM commands */ /* devices that don't properly handle queued TRIM commands */
{ "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, }, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, }, ATA_HORKAGE_ZERO_AFTER_TRIM, },
...@@ -6456,12 +6456,7 @@ static int __init ata_parse_force_one(char **cur, ...@@ -6456,12 +6456,7 @@ static int __init ata_parse_force_one(char **cur,
struct ata_force_ent *force_ent, struct ata_force_ent *force_ent,
const char **reason) const char **reason)
{ {
/* FIXME: Currently, there's no way to tag init const data and static const struct ata_force_param force_tbl[] __initconst = {
* using __initdata causes build failure on some versions of
* gcc. Once __initdataconst is implemented, add const to the
* following structure.
*/
static struct ata_force_param force_tbl[] __initdata = {
{ "40c", .cbl = ATA_CBL_PATA40 }, { "40c", .cbl = ATA_CBL_PATA40 },
{ "80c", .cbl = ATA_CBL_PATA80 }, { "80c", .cbl = ATA_CBL_PATA80 },
{ "short40c", .cbl = ATA_CBL_PATA40_SHORT }, { "short40c", .cbl = ATA_CBL_PATA40_SHORT },
...@@ -6472,6 +6467,8 @@ static int __init ata_parse_force_one(char **cur, ...@@ -6472,6 +6467,8 @@ static int __init ata_parse_force_one(char **cur,
{ "3.0Gbps", .spd_limit = 2 }, { "3.0Gbps", .spd_limit = 2 },
{ "noncq", .horkage_on = ATA_HORKAGE_NONCQ }, { "noncq", .horkage_on = ATA_HORKAGE_NONCQ },
{ "ncq", .horkage_off = ATA_HORKAGE_NONCQ }, { "ncq", .horkage_off = ATA_HORKAGE_NONCQ },
{ "noncqtrim", .horkage_on = ATA_HORKAGE_NO_NCQ_TRIM },
{ "ncqtrim", .horkage_off = ATA_HORKAGE_NO_NCQ_TRIM },
{ "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID }, { "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID },
{ "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) }, { "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
{ "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) }, { "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
......
...@@ -1507,16 +1507,21 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, ...@@ -1507,16 +1507,21 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
{ {
struct ata_taskfile tf; struct ata_taskfile tf;
unsigned int err_mask; unsigned int err_mask;
bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page); DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
retry:
ata_tf_init(dev, &tf); ata_tf_init(dev, &tf);
if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id)) { if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
!(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
tf.command = ATA_CMD_READ_LOG_DMA_EXT; tf.command = ATA_CMD_READ_LOG_DMA_EXT;
tf.protocol = ATA_PROT_DMA; tf.protocol = ATA_PROT_DMA;
dma = true;
} else { } else {
tf.command = ATA_CMD_READ_LOG_EXT; tf.command = ATA_CMD_READ_LOG_EXT;
tf.protocol = ATA_PROT_PIO; tf.protocol = ATA_PROT_PIO;
dma = false;
} }
tf.lbal = log; tf.lbal = log;
tf.lbam = page; tf.lbam = page;
...@@ -1527,6 +1532,12 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, ...@@ -1527,6 +1532,12 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
buf, sectors * ATA_SECT_SIZE, 0); buf, sectors * ATA_SECT_SIZE, 0);
if (err_mask && dma) {
dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
goto retry;
}
DPRINTK("EXIT, err_mask=%x\n", err_mask); DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask; return err_mask;
} }
......
...@@ -560,6 +560,27 @@ show_ata_dev_gscr(struct device *dev, ...@@ -560,6 +560,27 @@ show_ata_dev_gscr(struct device *dev,
static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL); static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
static ssize_t
show_ata_dev_trim(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ata_device *ata_dev = transport_class_to_dev(dev);
unsigned char *mode;
if (!ata_id_has_trim(ata_dev->id))
mode = "unsupported";
else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM)
mode = "forced_unqueued";
else if (ata_fpdma_dsm_supported(ata_dev))
mode = "queued";
else
mode = "unqueued";
return snprintf(buf, 20, "%s\n", mode);
}
static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL);
static DECLARE_TRANSPORT_CLASS(ata_dev_class, static DECLARE_TRANSPORT_CLASS(ata_dev_class,
"ata_device", NULL, NULL, NULL); "ata_device", NULL, NULL, NULL);
...@@ -733,6 +754,7 @@ struct scsi_transport_template *ata_attach_transport(void) ...@@ -733,6 +754,7 @@ struct scsi_transport_template *ata_attach_transport(void)
SETUP_DEV_ATTRIBUTE(ering); SETUP_DEV_ATTRIBUTE(ering);
SETUP_DEV_ATTRIBUTE(id); SETUP_DEV_ATTRIBUTE(id);
SETUP_DEV_ATTRIBUTE(gscr); SETUP_DEV_ATTRIBUTE(gscr);
SETUP_DEV_ATTRIBUTE(trim);
BUG_ON(count > ATA_DEV_ATTRS); BUG_ON(count > ATA_DEV_ATTRS);
i->dev_attrs[count] = NULL; i->dev_attrs[count] = NULL;
......
...@@ -352,7 +352,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -352,7 +352,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}; };
const struct ata_port_info *ppi[] = { &info_hpt366, NULL }; const struct ata_port_info *ppi[] = { &info_hpt366, NULL };
void *hpriv = NULL; const void *hpriv = NULL;
u32 reg1; u32 reg1;
int rc; int rc;
...@@ -383,7 +383,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -383,7 +383,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
break; break;
} }
/* Now kick off ATA set up */ /* Now kick off ATA set up */
return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0); return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, (void *)hpriv, 0);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
...@@ -638,7 +638,7 @@ static const struct dev_pm_ops pata_s3c_pm_ops = { ...@@ -638,7 +638,7 @@ static const struct dev_pm_ops pata_s3c_pm_ops = {
#endif #endif
/* driver device registration */ /* driver device registration */
static struct platform_device_id pata_s3c_driver_ids[] = { static const struct platform_device_id pata_s3c_driver_ids[] = {
{ {
.name = "s3c64xx-pata", .name = "s3c64xx-pata",
.driver_data = TYPE_S3C64XX, .driver_data = TYPE_S3C64XX,
......
...@@ -499,6 +499,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) ...@@ -499,6 +499,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
hpriv->irq = irq;
hpriv->flags |= (unsigned long)pi.private_data; hpriv->flags |= (unsigned long)pi.private_data;
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
...@@ -568,7 +569,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) ...@@ -568,7 +569,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
ahci_init_controller(host); ahci_init_controller(host);
ahci_print_info(host, "platform"); ahci_print_info(host, "platform");
rc = ahci_host_activate(host, irq, &ahci_highbank_platform_sht); rc = ahci_host_activate(host, &ahci_highbank_platform_sht);
if (rc) if (rc)
goto err0; goto err0;
......
...@@ -599,7 +599,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl); ...@@ -599,7 +599,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
static bool adma_enabled; static bool adma_enabled;
static bool swncq_enabled = 1; static bool swncq_enabled = true;
static bool msi_enabled; static bool msi_enabled;
static void nv_adma_register_mode(struct ata_port *ap) static void nv_adma_register_mode(struct ata_port *ap)
......
...@@ -704,9 +704,19 @@ static inline bool ata_id_wcache_enabled(const u16 *id) ...@@ -704,9 +704,19 @@ static inline bool ata_id_wcache_enabled(const u16 *id)
static inline bool ata_id_has_read_log_dma_ext(const u16 *id) static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
{ {
/* Word 86 must have bit 15 set */
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15))) if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
return false; return false;
return id[ATA_ID_COMMAND_SET_3] & (1 << 3);
/* READ LOG DMA EXT support can be signaled either from word 119
* or from word 120. The format is the same for both words: Bit
* 15 must be cleared, bit 14 set and bit 3 set.
*/
if ((id[ATA_ID_COMMAND_SET_3] & 0xC008) == 0x4008 ||
(id[ATA_ID_COMMAND_SET_4] & 0xC008) == 0x4008)
return true;
return false;
} }
static inline bool ata_id_has_sense_reporting(const u16 *id) static inline bool ata_id_has_sense_reporting(const u16 *id)
......
...@@ -430,6 +430,7 @@ enum { ...@@ -430,6 +430,7 @@ enum {
ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */
ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */
ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */ ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */
ATA_HORKAGE_NO_NCQ_LOG = (1 << 23), /* don't use NCQ for log read */
/* DMA mask for user DMA control: User visible values; DO NOT /* DMA mask for user DMA control: User visible values; DO NOT
renumber */ renumber */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment