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. ...
This commit is contained in:
commit
64e22b8685
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
* 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,
|
||||
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;
|
||||
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;
|
||||
|
||||
intx:
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* 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");
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* 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 @@ softreset_retry:
|
|||
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_ops,
|
||||
.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_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 @@ disable_resources:
|
|||
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,27 +1825,9 @@ 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)
|
||||
{
|
||||
struct ata_host *host = dev_instance;
|
||||
struct ahci_host_priv *hpriv;
|
||||
unsigned int i, handled = 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);
|
||||
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
struct ata_port *ap;
|
||||
|
@ -1867,6 +1849,70 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
|
|||
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 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
rc = ahci_handle_port_intr(host, irq_masked);
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
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;
|
||||
* otherwise, it will raise a spurious interrupt after each
|
||||
|
@ -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 @@ out_free_irqs:
|
|||
/**
|
||||
* 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 */
|
||||
|
|
Loading…
Reference in New Issue