Merge branch 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 25 Jun 2015 23:49:21 +0000 (16:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 25 Jun 2015 23:49:21 +0000 (16:49 -0700)
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.
  ...

26 files changed:
Documentation/ABI/testing/sysfs-ata
Documentation/devicetree/bindings/ata/ahci-ceva.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/acard-ahci.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_brcmstb.c [new file with mode: 0644]
drivers/ata/ahci_ceva.c [new file with mode: 0644]
drivers/ata/ahci_mvebu.c
drivers/ata/ahci_platform.c
drivers/ata/ahci_xgene.c
drivers/ata/libahci.c
drivers/ata/libahci_platform.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-transport.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_samsung_cf.c
drivers/ata/sata_highbank.c
drivers/ata/sata_nv.c
include/linux/ata.h
include/linux/libata.h

index 0a932155cbbafc6eb87387125dc417f72707a767..aa4296498859e49617cc7fc6f377c6dcb7a8f6c1 100644 (file)
@@ -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.
diff --git a/Documentation/devicetree/bindings/ata/ahci-ceva.txt b/Documentation/devicetree/bindings/ata/ahci-ceva.txt
new file mode 100644 (file)
index 0000000..7ca8b97
--- /dev/null
@@ -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;
+       };
index c2340eeeb97ff072196dbcd49144897813b1573d..a2321819e7f5fb1613fa8c4ef3b092e87fe4e647 100644 (file)
@@ -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>
diff --git a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
new file mode 100644 (file)
index 0000000..20ac9bb
--- /dev/null
@@ -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>;
+               };
+       };
index fd66d220c115f11fba4ab26a5a2898eb687a2bb9..c84d078a6376159f4d28ea71b2550a20abdb8c63 100644 (file)
@@ -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.
 
index 9dca4b995be0792b6c4f1920b9786cb6517a2b5f..b11470a7bd8f870912b44fce0bdff1eba8ebd7c7 100644 (file)
@@ -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
index 40f7865f20a1dbf62123da6998fcef81fa9a2690..af70919f7ddef6cc0c3e52763a843ada5c6656ac 100644 (file)
@@ -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
index 12489ce863c4bf06c06a38aa182124785346e365..ed6a30cd681a047276e5f782aa603ca9c47c3315 100644 (file)
@@ -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);
index 65ee94454bbd2c92f1879386b19a346a5632794f..7e62751abfacce2aaca99c7b08834f2464b46498 100644 (file)
@@ -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)
-               goto intx;
+               return -ENODEV;
+
+       nvec = pci_msix_vec_count(pdev);
+       if (nvec < 0)
+               return nvec;
+
+       if (!nvec) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       /*
+        * There can be more than one vector (e.g. for error detection or
+        * hdd hotplug). Only the first vector (entry.entry = 0) is used.
+        */
+       rc = pci_enable_msix_exact(pdev, &entry, 1);
+       if (rc < 0)
+               goto fail;
+
+       hpriv->irq = entry.vector;
+
+       return 1;
+fail:
+       dev_err(&pdev->dev,
+               "failed to enable MSI-X with error %d, # of vectors: %d\n",
+               rc, nvec);
+
+       return rc;
+}
+
+static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
+                       struct ahci_host_priv *hpriv)
+{
+       int rc, nvec;
+
+       if (hpriv->flags & AHCI_HFLAG_NO_MSI)
+               return -ENODEV;
 
        nvec = pci_msi_vec_count(pdev);
        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;
+
+       return nvec;
+}
+
+static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
+                               struct ahci_host_priv *hpriv)
+{
+       int nvec;
+
+       nvec = ahci_init_msi(pdev, n_ports, hpriv);
+       if (nvec >= 0)
+               return nvec;
+
+       /*
+        * Currently, MSI-X support only implements single IRQ mode and
+        * exists for controllers which can't do other types of IRQ. Only
+        * set it up if MSI fails.
+        */
+       nvec = ahci_init_msix(pdev, n_ports, hpriv);
+       if (nvec >= 0)
+               return nvec;
 
-intx:
+       /* lagacy intx interrupts */
        pci_intx(pdev, 1);
+       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);
index 71262e08648e72d786cf8dca1f6bb338bee4375c..5b8e8a0fab487a8fdce58066c347df6759b31bee 100644 (file)
@@ -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,
diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c
new file mode 100644 (file)
index 0000000..ce1e3a8
--- /dev/null
@@ -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");
diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c
new file mode 100644 (file)
index 0000000..207649d
--- /dev/null
@@ -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");
index 5928d0746a270e7b6b2ee12a022b19ed731f03fe..8490d37aee2a466809c2634e51e8b96386e2eecb 100644 (file)
@@ -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,
index 78d6ae0b90c400f807f18cdd6f4b6d214d175a32..614c78f510f049286f491d78ec9f3d395300a6f2 100644 (file)
@@ -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);
index 2b78510d94dd7732f7231d0348d7a1f0818a427a..e2c6d9e0c5ac5ce5ce389b0ae1b0597ae979ee8b 100644 (file)
@@ -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"
 /* 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_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 @@ 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,
index 287c4ba0219f7ced8c76af999dd1eeb3e5ed2639..d256a66158be838bb7b312dcda96f6ecad97e332 100644 (file)
@@ -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 @@ 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;
 }
index d89305d289f63f8a4afcb78773a19e42088790ba..aaa761b9081cc02a75792302c741f7b54ebd9823 100644 (file)
@@ -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);
 
index 577849c6611ac5efa2c948c7b274dc894a19890d..e83fc3d0da9c9c60a99a6dec56cc568a97a0a851 100644 (file)
@@ -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) },
index cf0022ec07f2420c37fb8a52dc904530f0df2e38..7465031a893c60c9e61f2c911abf218b39c81d2e 100644 (file)
@@ -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;
 }
index 3227b7c8a05f88bf040dfefd61b4382583d1368a..d6c37bcd416d17145f291136b6e5f2a7192ee404 100644 (file)
@@ -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;
 
index cbc3de793d1d61a494cb82fe76e6a16ebfb8ab5b..0038dc4c06c7dbd89b7cef8f424f374fc250da42 100644 (file)
@@ -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
index fa44eb2872db9164dced31d3fb8f3b217740e5db..cbb5a471eb9d05c39b15ea1ab6c87fa1e4ee7464 100644 (file)
@@ -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,
index 24e311fe2c1c3ebf90431b99f67e5ac09cb2c572..8638d575b2b99baef3d9a429e99fbc5287b4f1e1 100644 (file)
@@ -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;
 
index 7ece85f43020967a9f9b3b5657bf7ce50ae22c9f..734f563b8d37b076f6795c32337cd58d76fd9b84 100644 (file)
@@ -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)
index b666b773e1118bb28171554d7e1846144f07d050..fed36418dd1c2fe8c1c084278080f2ff23169725 100644 (file)
@@ -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)
index 51cb312d9bb9786682d3255f8a0cac6d9f670ce0..36ce37bcc963c270548989d658caa4f3ce832045 100644 (file)
@@ -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 */