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
130: SATA_PMP_GSCR_SII_GPIO
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
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:
- "snps,dwc-ahci"
- "snps,exynos5440-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"
- interrupts : <interrupt mapping for SATA IRQ>
- 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.
* [no]ncq: Turn on or off NCQ.
* [no]ncqtrim: Turn off queued DSM TRIM.
* nohrst, nosrst, norst: suppress hard, soft
and both resets.
......
......@@ -98,6 +98,15 @@ config SATA_AHCI_PLATFORM
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
tristate "DaVinci DA850 AHCI SATA support"
depends on ARCH_DAVINCI_DA850
......@@ -124,6 +133,15 @@ config AHCI_IMX
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
tristate "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU
......
......@@ -10,6 +10,8 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.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_IMX) += ahci_imx.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
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
hpriv->irq = pdev->irq;
hpriv->flags |= (unsigned long)pi.private_data;
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
acard_ahci_pci_print_info(host);
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);
......
......@@ -42,6 +42,7 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/gfp.h>
#include <linux/msi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
......@@ -52,6 +53,7 @@
enum {
AHCI_PCI_BAR_STA2X11 = 0,
AHCI_PCI_BAR_CAVIUM = 0,
AHCI_PCI_BAR_ENMOTUS = 2,
AHCI_PCI_BAR_STANDARD = 5,
};
......@@ -1288,17 +1290,60 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
/*
* 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;
struct msix_entry entry = {};
/* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
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)
goto intx;
return -ENODEV;
nvec = pci_msi_vec_count(pdev);
if (nvec < 0)
goto intx;
return nvec;
/*
* 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,
rc = pci_enable_msi_exact(pdev, nvec);
if (rc == -ENOSPC)
goto single_msi;
else if (rc < 0)
goto intx;
if (rc < 0)
return rc;
/* fallback to single MSI mode if the controller enforced MRSM mode */
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,
if (nvec > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
return nvec;
goto out;
single_msi:
if (pci_enable_msi(pdev))
goto intx;
return 1;
nvec = 1;
rc = pci_enable_msi(pdev);
if (rc < 0)
return rc;
out:
hpriv->irq = pdev->irq;
intx:
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;
/* lagacy intx interrupts */
pci_intx(pdev, 1);
hpriv->irq = pdev->irq;
return 0;
}
......@@ -1371,11 +1443,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev,
"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)
ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
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
......@@ -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));
ahci_init_interrupts(pdev, n_ports, hpriv);
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
host->private_data = hpriv;
ahci_init_interrupts(pdev, n_ports, hpriv);
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN;
else
......@@ -1549,7 +1623,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
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);
......
......@@ -238,6 +238,8 @@ enum {
AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
Edge Triggered */
/* ap->flags bits */
......@@ -341,6 +343,7 @@ struct ahci_host_priv {
struct phy **phys;
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
/*
* Optional ahci_start_engine override, if not set this gets set to the
* 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,
struct ata_port_info *pi);
int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s);
int ahci_host_activate(struct ata_host *host, int irq,
struct scsi_host_template *sht);
int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
void ahci_error_handler(struct ata_port *ap);
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)
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 = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
......@@ -120,6 +140,8 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);
static struct platform_driver ahci_mvebu_driver = {
.probe = ahci_mvebu_probe,
.remove = ata_platform_remove_one,
.suspend = ahci_mvebu_suspend,
.resume = ahci_mvebu_resume,
.driver = {
.name = DRV_NAME,
.of_match_table = ahci_mvebu_of_match,
......
......@@ -74,6 +74,7 @@ static const struct of_device_id ahci_of_match[] = {
{ .compatible = "ibm,476gtr-ahci", },
{ .compatible = "snps,dwc-ahci", },
{ .compatible = "hisilicon,hisi-ahci", },
{ .compatible = "fsl,qoriq-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
......
......@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/ahci_platform.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/phy/phy.h>
#include "ahci.h"
......@@ -84,6 +85,11 @@
/* Max retry for link down */
#define MAX_LINK_DOWN_RETRY 3
enum xgene_ahci_version {
XGENE_AHCI_V1 = 1,
XGENE_AHCI_V2,
};
struct xgene_ahci_context {
struct ahci_host_priv *hpriv;
struct device *dev;
......@@ -542,7 +548,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
return rc;
}
static struct ata_port_operations xgene_ahci_ops = {
static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset,
......@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = {
.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,
.pio_mask = ATA_PIO4,
.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)
......@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = {
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)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct xgene_ahci_context *ctx;
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;
hpriv = ahci_platform_get_resources(pdev);
......@@ -677,6 +717,35 @@ static int xgene_ahci_probe(struct platform_device *pdev)
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,
hpriv->mmio);
......@@ -704,9 +773,19 @@ static int xgene_ahci_probe(struct platform_device *pdev)
/* Configure the host controller */
xgene_ahci_hw_init(hpriv);
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);
if (rc)
goto disable_resources;
......@@ -719,20 +798,6 @@ static int xgene_ahci_probe(struct platform_device *pdev)
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 = {
.probe = xgene_ahci_probe,
.remove = ata_platform_remove_one,
......
......@@ -1825,11 +1825,38 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
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 ahci_host_priv *hpriv;
unsigned int i, handled = 0;
unsigned int rc = 0;
void __iomem *mmio;
u32 irq_stat, irq_masked;
......@@ -1847,25 +1874,44 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
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)))
continue;
rc = ahci_handle_port_intr(host, irq_masked);
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);
}
spin_unlock(&host->lock);
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
* 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)
VPRINTK("EXIT\n");
return IRQ_RETVAL(handled);
return IRQ_RETVAL(rc);
}
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
......@@ -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.
*/
if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
spin_lock_init(&pp->lock);
ap->lock = &pp->lock;
}
......@@ -2425,7 +2471,10 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
rc = ata_host_start(host);
if (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++) {
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,
/**
* ahci_host_activate - start AHCI host, request IRQs and register it
* @host: target ATA host
* @irq: base IRQ number to request
* @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:
* Inherited from calling layer (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ahci_host_activate(struct ata_host *host, int irq,
struct scsi_host_template *sht)
int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
{
struct ahci_host_priv *hpriv = host->private_data;
int irq = hpriv->irq;
int rc;
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
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
rc = ata_host_activate(host, irq, ahci_single_irq_intr,
rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
IRQF_SHARED, sht);
return rc;
}
......
......@@ -518,6 +518,8 @@ int ahci_platform_init_host(struct platform_device *pdev,
return -EINVAL;
}
hpriv->irq = irq;
/* prepare host */
pi.private_data = (void *)(unsigned long)hpriv->flags;
......@@ -588,7 +590,7 @@ int ahci_platform_init_host(struct platform_device *pdev,
ahci_init_controller(host);
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);
......
......@@ -3654,7 +3654,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* EH context.
*
* 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,
bool spm_wakeup)
......@@ -4225,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
/* 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, },
{ "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
......@@ -6456,12 +6456,7 @@ static int __init ata_parse_force_one(char **cur,
struct ata_force_ent *force_ent,
const char **reason)
{
/* FIXME: Currently, there's no way to tag init const data and
* 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 = {
static const struct ata_force_param force_tbl[] __initconst = {
{ "40c", .cbl = ATA_CBL_PATA40 },
{ "80c", .cbl = ATA_CBL_PATA80 },
{ "short40c", .cbl = ATA_CBL_PATA40_SHORT },
......@@ -6472,6 +6467,8 @@ static int __init ata_parse_force_one(char **cur,
{ "3.0Gbps", .spd_limit = 2 },
{ "noncq", .horkage_on = 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 },
{ "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
{ "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
......
......@@ -1507,16 +1507,21 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
{
struct ata_taskfile tf;
unsigned int err_mask;
bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
retry:
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.protocol = ATA_PROT_DMA;
dma = true;
} else {
tf.command = ATA_CMD_READ_LOG_EXT;
tf.protocol = ATA_PROT_PIO;
dma = false;
}
tf.lbal = log;
tf.lbam = page;
......@@ -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,
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);
return err_mask;
}
......
......@@ -560,6 +560,27 @@ show_ata_dev_gscr(struct device *dev,
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,
"ata_device", NULL, NULL, NULL);
......@@ -733,6 +754,7 @@ struct scsi_transport_template *ata_attach_transport(void)
SETUP_DEV_ATTRIBUTE(ering);
SETUP_DEV_ATTRIBUTE(id);
SETUP_DEV_ATTRIBUTE(gscr);
SETUP_DEV_ATTRIBUTE(trim);
BUG_ON(count > ATA_DEV_ATTRS);
i->dev_attrs[count] = NULL;
......
......@@ -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 };
void *hpriv = NULL;
const void *hpriv = NULL;
u32 reg1;
int rc;
......@@ -383,7 +383,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
break;
}
/* 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
......
......@@ -638,7 +638,7 @@ static const struct dev_pm_ops pata_s3c_pm_ops = {
#endif
/* 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",
.driver_data = TYPE_S3C64XX,
......
......@@ -499,6 +499,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
return -ENOMEM;
}
hpriv->irq = irq;
hpriv->flags |= (unsigned long)pi.private_data;
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
......@@ -568,7 +569,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
ahci_init_controller(host);
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)
goto err0;
......
......@@ -599,7 +599,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
static bool adma_enabled;
static bool swncq_enabled = 1;
static bool swncq_enabled = true;
static bool msi_enabled;
static void nv_adma_register_mode(struct ata_port *ap)
......
......@@ -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)
{
/* Word 86 must have bit 15 set */
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
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)
......
......@@ -430,6 +430,7 @@ enum {
ATA_HORKAGE_NOLPM = (1 << 20), /* don't use 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_NO_NCQ_LOG = (1 << 23), /* don't use NCQ for log read */
/* DMA mask for user DMA control: User visible values; DO NOT
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