]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/ata/sata_mv.c
Merge branch 'core/percpu' into percpu-cpumask-x86-for-linus-2
[mv-sheeva.git] / drivers / ata / sata_mv.c
index 1f14b1b52340dfce4e4136f694e2d3ede81ab173..a377226b81c8954005f37cfaac9aeb69ebff1677 100644 (file)
@@ -1,10 +1,13 @@
 /*
  * sata_mv.c - Marvell SATA support
  *
- * Copyright 2008: Marvell Corporation, all rights reserved.
+ * Copyright 2008-2009: Marvell Corporation, all rights reserved.
  * Copyright 2005: EMC Corporation, all rights reserved.
  * Copyright 2005 Red Hat, Inc.  All rights reserved.
  *
+ * Originally written by Brett Russ.
+ * Extensive overhaul and enhancement by Mark Lord <mlord@pobox.com>.
+ *
  * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
  *
  * This program is free software; you can redistribute it and/or modify
 /*
  * sata_mv TODO list:
  *
- * --> Errata workaround for NCQ device errors.
- *
  * --> More errata workarounds for PCI-X.
  *
  * --> Complete a full errata audit for all chipsets to identify others.
  *
  * --> Develop a low-power-consumption strategy, and implement it.
  *
- * --> [Experiment, low priority] Investigate interrupt coalescing.
- *       Quite often, especially with PCI Message Signalled Interrupts (MSI),
- *       the overhead reduced by interrupt mitigation is quite often not
- *       worth the latency cost.
+ * --> Add sysfs attributes for per-chip / per-HC IRQ coalescing thresholds.
  *
  * --> [Experiment, Marvell value added] Is it possible to use target
  *       mode to cross-connect two Linux boxes with Marvell cards?  If so,
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "1.26"
+#define DRV_VERSION    "1.27"
+
+/*
+ * module options
+ */
+
+static int msi;
+#ifdef CONFIG_PCI
+module_param(msi, int, S_IRUGO);
+MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+#endif
+
+static int irq_coalescing_io_count;
+module_param(irq_coalescing_io_count, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_io_count,
+                "IRQ coalescing I/O count threshold (0..255)");
+
+static int irq_coalescing_usecs;
+module_param(irq_coalescing_usecs, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_usecs,
+                "IRQ coalescing time threshold in usecs");
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -77,13 +95,32 @@ enum {
        MV_MAJOR_REG_AREA_SZ    = 0x10000,      /* 64KB */
        MV_MINOR_REG_AREA_SZ    = 0x2000,       /* 8KB */
 
+       /* For use with both IRQ coalescing methods ("all ports" or "per-HC" */
+       COAL_CLOCKS_PER_USEC    = 150,          /* for calculating COAL_TIMEs */
+       MAX_COAL_TIME_THRESHOLD = ((1 << 24) - 1), /* internal clocks count */
+       MAX_COAL_IO_COUNT       = 255,          /* completed I/O count */
+
        MV_PCI_REG_BASE         = 0,
-       MV_IRQ_COAL_REG_BASE    = 0x18000,      /* 6xxx part only */
-       MV_IRQ_COAL_CAUSE               = (MV_IRQ_COAL_REG_BASE + 0x08),
-       MV_IRQ_COAL_CAUSE_LO            = (MV_IRQ_COAL_REG_BASE + 0x88),
-       MV_IRQ_COAL_CAUSE_HI            = (MV_IRQ_COAL_REG_BASE + 0x8c),
-       MV_IRQ_COAL_THRESHOLD           = (MV_IRQ_COAL_REG_BASE + 0xcc),
-       MV_IRQ_COAL_TIME_THRESHOLD      = (MV_IRQ_COAL_REG_BASE + 0xd0),
+
+       /*
+        * Per-chip ("all ports") interrupt coalescing feature.
+        * This is only for GEN_II / GEN_IIE hardware.
+        *
+        * Coalescing defers the interrupt until either the IO_THRESHOLD
+        * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+        */
+       MV_COAL_REG_BASE        = 0x18000,
+       MV_IRQ_COAL_CAUSE       = (MV_COAL_REG_BASE + 0x08),
+       ALL_PORTS_COAL_IRQ      = (1 << 4),     /* all ports irq event */
+
+       MV_IRQ_COAL_IO_THRESHOLD   = (MV_COAL_REG_BASE + 0xcc),
+       MV_IRQ_COAL_TIME_THRESHOLD = (MV_COAL_REG_BASE + 0xd0),
+
+       /*
+        * Registers for the (unused here) transaction coalescing feature:
+        */
+       MV_TRAN_COAL_CAUSE_LO   = (MV_COAL_REG_BASE + 0x88),
+       MV_TRAN_COAL_CAUSE_HI   = (MV_COAL_REG_BASE + 0x8c),
 
        MV_SATAHC0_REG_BASE     = 0x20000,
        MV_FLASH_CTL_OFS        = 0x1046c,
@@ -115,16 +152,14 @@ enum {
 
        /* Host Flags */
        MV_FLAG_DUAL_HC         = (1 << 30),  /* two SATA Host Controllers */
-       MV_FLAG_IRQ_COALESCE    = (1 << 29),  /* IRQ coalescing capability */
 
        MV_COMMON_FLAGS         = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
 
        MV_GEN_I_FLAGS          = MV_COMMON_FLAGS | ATA_FLAG_NO_ATAPI,
 
-       MV_GEN_II_FLAGS         = MV_COMMON_FLAGS | MV_FLAG_IRQ_COALESCE |
-                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
-                                 ATA_FLAG_NCQ,
+       MV_GEN_II_FLAGS         = MV_COMMON_FLAGS | ATA_FLAG_NCQ |
+                                 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA,
 
        MV_GEN_IIE_FLAGS        = MV_GEN_II_FLAGS | ATA_FLAG_AN,
 
@@ -179,16 +214,18 @@ enum {
        PCI_HC_MAIN_IRQ_MASK_OFS  = 0x1d64,
        SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020,
        SOC_HC_MAIN_IRQ_MASK_OFS  = 0x20024,
-       ERR_IRQ                 = (1 << 0),     /* shift by port # */
-       DONE_IRQ                = (1 << 1),     /* shift by port # */
+       ERR_IRQ                 = (1 << 0),     /* shift by (2 * port #) */
+       DONE_IRQ                = (1 << 1),     /* shift by (2 * port #) */
        HC0_IRQ_PEND            = 0x1ff,        /* bits 0-8 = HC0's ports */
        HC_SHIFT                = 9,            /* bits 9-17 = HC1's ports */
+       DONE_IRQ_0_3            = 0x000000aa,   /* DONE_IRQ ports 0,1,2,3 */
+       DONE_IRQ_4_7            = (DONE_IRQ_0_3 << HC_SHIFT),  /* 4,5,6,7 */
        PCI_ERR                 = (1 << 18),
-       TRAN_LO_DONE            = (1 << 19),    /* 6xxx: IRQ coalescing */
-       TRAN_HI_DONE            = (1 << 20),    /* 6xxx: IRQ coalescing */
-       PORTS_0_3_COAL_DONE     = (1 << 8),
-       PORTS_4_7_COAL_DONE     = (1 << 17),
-       PORTS_0_7_COAL_DONE     = (1 << 21),    /* 6xxx: IRQ coalescing */
+       TRAN_COAL_LO_DONE       = (1 << 19),    /* transaction coalescing */
+       TRAN_COAL_HI_DONE       = (1 << 20),    /* transaction coalescing */
+       PORTS_0_3_COAL_DONE     = (1 << 8),     /* HC0 IRQ coalescing */
+       PORTS_4_7_COAL_DONE     = (1 << 17),    /* HC1 IRQ coalescing */
+       ALL_PORTS_COAL_DONE     = (1 << 21),    /* GEN_II(E) IRQ coalescing */
        GPIO_INT                = (1 << 22),
        SELF_INT                = (1 << 23),
        TWSI_INT                = (1 << 24),
@@ -204,6 +241,21 @@ enum {
        HC_COAL_IRQ             = (1 << 4),     /* IRQ coalescing */
        DEV_IRQ                 = (1 << 8),     /* shift by port # */
 
+       /*
+        * Per-HC (Host-Controller) interrupt coalescing feature.
+        * This is present on all chip generations.
+        *
+        * Coalescing defers the interrupt until either the IO_THRESHOLD
+        * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+        */
+       HC_IRQ_COAL_IO_THRESHOLD_OFS    = 0x000c,
+       HC_IRQ_COAL_TIME_THRESHOLD_OFS  = 0x0010,
+
+       SOC_LED_CTRL_OFS        = 0x2c,
+       SOC_LED_CTRL_BLINK      = (1 << 0),     /* Active LED blink */
+       SOC_LED_CTRL_ACT_PRESENCE = (1 << 2),   /* Multiplex dev presence */
+                                               /*  with dev activity LED */
+
        /* Shadow block registers */
        SHD_BLK_OFS             = 0x100,
        SHD_CTL_AST_OFS         = 0x20,         /* ofs from SHD_BLK_OFS */
@@ -345,7 +397,7 @@ enum {
        EDMA_ARB_CFG_OFS        = 0x38,
 
        EDMA_HALTCOND_OFS       = 0x60,         /* GenIIe halt conditions */
-
+       EDMA_UNKNOWN_RSVD_OFS   = 0x6C,         /* GenIIe unknown/reserved */
 
        BMDMA_CMD_OFS           = 0x224,        /* bmdma command register */
        BMDMA_STATUS_OFS        = 0x228,        /* bmdma status register */
@@ -364,12 +416,14 @@ enum {
        MV_HP_PCIE              = (1 << 9),     /* PCIe bus/regs: 7042 */
        MV_HP_CUT_THROUGH       = (1 << 10),    /* can use EDMA cut-through */
        MV_HP_FLAG_SOC          = (1 << 11),    /* SystemOnChip, no PCI */
+       MV_HP_QUIRK_LED_BLINK_EN = (1 << 12),   /* is led blinking enabled? */
 
        /* Port private flags (pp_flags) */
        MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
        MV_PP_FLAG_NCQ_EN       = (1 << 1),     /* is EDMA set up for NCQ? */
        MV_PP_FLAG_FBS_EN       = (1 << 2),     /* is EDMA set up for FBS? */
        MV_PP_FLAG_DELAYED_EH   = (1 << 3),     /* delayed dev err handling */
+       MV_PP_FLAG_FAKE_ATA_BUSY = (1 << 4),    /* ignore initial ATA_DRDY */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -438,6 +492,18 @@ struct mv_sg {
        __le32                  reserved;
 };
 
+/*
+ * We keep a local cache of a few frequently accessed port
+ * registers here, to avoid having to read them (very slow)
+ * when switching between EDMA and non-EDMA modes.
+ */
+struct mv_cached_regs {
+       u32                     fiscfg;
+       u32                     ltmode;
+       u32                     haltcond;
+       u32                     unknown_rsvd;
+};
+
 struct mv_port_priv {
        struct mv_crqb          *crqb;
        dma_addr_t              crqb_dma;
@@ -450,6 +516,7 @@ struct mv_port_priv {
        unsigned int            resp_idx;
 
        u32                     pp_flags;
+       struct mv_cached_regs   cached;
        unsigned int            delayed_eh_pmp_map;
 };
 
@@ -551,14 +618,13 @@ static void mv_pmp_error_handler(struct ata_port *ap);
 static void mv_process_crpb_entries(struct ata_port *ap,
                                        struct mv_port_priv *pp);
 
-static unsigned long mv_mode_filter(struct ata_device *dev,
-                                   unsigned long xfer_mask);
 static void mv_sff_irq_clear(struct ata_port *ap);
 static int mv_check_atapi_dma(struct ata_queued_cmd *qc);
 static void mv_bmdma_setup(struct ata_queued_cmd *qc);
 static void mv_bmdma_start(struct ata_queued_cmd *qc);
 static void mv_bmdma_stop(struct ata_queued_cmd *qc);
 static u8   mv_bmdma_status(struct ata_port *ap);
+static u8 mv_sff_check_status(struct ata_port *ap);
 
 /* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
  * because we have to allow room for worst case splitting of
@@ -580,6 +646,8 @@ static struct scsi_host_template mv6_sht = {
 static struct ata_port_operations mv5_ops = {
        .inherits               = &ata_sff_port_ops,
 
+       .lost_interrupt         = ATA_OP_NULL,
+
        .qc_defer               = mv_qc_defer,
        .qc_prep                = mv_qc_prep,
        .qc_issue               = mv_qc_issue,
@@ -608,13 +676,13 @@ static struct ata_port_operations mv6_ops = {
        .softreset              = mv_softreset,
        .error_handler          = mv_pmp_error_handler,
 
+       .sff_check_status       = mv_sff_check_status,
        .sff_irq_clear          = mv_sff_irq_clear,
        .check_atapi_dma        = mv_check_atapi_dma,
        .bmdma_setup            = mv_bmdma_setup,
        .bmdma_start            = mv_bmdma_start,
        .bmdma_stop             = mv_bmdma_stop,
        .bmdma_status           = mv_bmdma_status,
-       .mode_filter            = mv_mode_filter,
 };
 
 static struct ata_port_operations mv_iie_ops = {
@@ -812,6 +880,44 @@ static inline int mv_get_hc_count(unsigned long port_flags)
        return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
 }
 
+/**
+ *      mv_save_cached_regs - (re-)initialize cached port registers
+ *      @ap: the port whose registers we are caching
+ *
+ *     Initialize the local cache of port registers,
+ *     so that reading them over and over again can
+ *     be avoided on the hotter paths of this driver.
+ *     This saves a few microseconds each time we switch
+ *     to/from EDMA mode to perform (eg.) a drive cache flush.
+ */
+static void mv_save_cached_regs(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       struct mv_port_priv *pp = ap->private_data;
+
+       pp->cached.fiscfg = readl(port_mmio + FISCFG_OFS);
+       pp->cached.ltmode = readl(port_mmio + LTMODE_OFS);
+       pp->cached.haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+       pp->cached.unknown_rsvd = readl(port_mmio + EDMA_UNKNOWN_RSVD_OFS);
+}
+
+/**
+ *      mv_write_cached_reg - write to a cached port register
+ *      @addr: hardware address of the register
+ *      @old: pointer to cached value of the register
+ *      @new: new value for the register
+ *
+ *     Write a new value to a cached register,
+ *     but only if the value is different from before.
+ */
+static inline void mv_write_cached_reg(void __iomem *addr, u32 *old, u32 new)
+{
+       if (new != *old) {
+               *old = new;
+               writel(new, addr);
+       }
+}
+
 static void mv_set_edma_ptrs(void __iomem *port_mmio,
                             struct mv_host_priv *hpriv,
                             struct mv_port_priv *pp)
@@ -843,6 +949,23 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
                 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 }
 
+static void mv_write_main_irq_mask(u32 mask, struct mv_host_priv *hpriv)
+{
+       /*
+        * When writing to the main_irq_mask in hardware,
+        * we must ensure exclusivity between the interrupt coalescing bits
+        * and the corresponding individual port DONE_IRQ bits.
+        *
+        * Note that this register is really an "IRQ enable" register,
+        * not an "IRQ mask" register as Marvell's naming might suggest.
+        */
+       if (mask & (ALL_PORTS_COAL_DONE | PORTS_0_3_COAL_DONE))
+               mask &= ~DONE_IRQ_0_3;
+       if (mask & (ALL_PORTS_COAL_DONE | PORTS_4_7_COAL_DONE))
+               mask &= ~DONE_IRQ_4_7;
+       writelfl(mask, hpriv->main_irq_mask_addr);
+}
+
 static void mv_set_main_irq_mask(struct ata_host *host,
                                 u32 disable_bits, u32 enable_bits)
 {
@@ -853,7 +976,7 @@ static void mv_set_main_irq_mask(struct ata_host *host,
        new_mask = (old_mask & ~disable_bits) | enable_bits;
        if (new_mask != old_mask) {
                hpriv->main_irq_mask = new_mask;
-               writelfl(new_mask, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(new_mask, hpriv);
        }
 }
 
@@ -894,6 +1017,68 @@ static void mv_clear_and_enable_port_irqs(struct ata_port *ap,
        mv_enable_port_irqs(ap, port_irqs);
 }
 
+static void mv_set_irq_coalescing(struct ata_host *host,
+                                 unsigned int count, unsigned int usecs)
+{
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->base, *hc_mmio;
+       u32 coal_enable = 0;
+       unsigned long flags;
+       unsigned int clks, is_dual_hc = hpriv->n_ports > MV_PORTS_PER_HC;
+       const u32 coal_disable = PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
+                                                       ALL_PORTS_COAL_DONE;
+
+       /* Disable IRQ coalescing if either threshold is zero */
+       if (!usecs || !count) {
+               clks = count = 0;
+       } else {
+               /* Respect maximum limits of the hardware */
+               clks = usecs * COAL_CLOCKS_PER_USEC;
+               if (clks > MAX_COAL_TIME_THRESHOLD)
+                       clks = MAX_COAL_TIME_THRESHOLD;
+               if (count > MAX_COAL_IO_COUNT)
+                       count = MAX_COAL_IO_COUNT;
+       }
+
+       spin_lock_irqsave(&host->lock, flags);
+       mv_set_main_irq_mask(host, coal_disable, 0);
+
+       if (is_dual_hc && !IS_GEN_I(hpriv)) {
+               /*
+                * GEN_II/GEN_IIE with dual host controllers:
+                * one set of global thresholds for the entire chip.
+                */
+               writel(clks,  mmio + MV_IRQ_COAL_TIME_THRESHOLD);
+               writel(count, mmio + MV_IRQ_COAL_IO_THRESHOLD);
+               /* clear leftover coal IRQ bit */
+               writel(~ALL_PORTS_COAL_IRQ, mmio + MV_IRQ_COAL_CAUSE);
+               if (count)
+                       coal_enable = ALL_PORTS_COAL_DONE;
+               clks = count = 0; /* force clearing of regular regs below */
+       }
+
+       /*
+        * All chips: independent thresholds for each HC on the chip.
+        */
+       hc_mmio = mv_hc_base_from_port(mmio, 0);
+       writel(clks,  hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD_OFS);
+       writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD_OFS);
+       writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE_OFS);
+       if (count)
+               coal_enable |= PORTS_0_3_COAL_DONE;
+       if (is_dual_hc) {
+               hc_mmio = mv_hc_base_from_port(mmio, MV_PORTS_PER_HC);
+               writel(clks,  hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD_OFS);
+               writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD_OFS);
+               writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE_OFS);
+               if (count)
+                       coal_enable |= PORTS_4_7_COAL_DONE;
+       }
+
+       mv_set_main_irq_mask(host, 0, coal_enable);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /**
  *      mv_start_edma - Enable eDMA engine
  *      @base: port base address
@@ -1159,35 +1344,33 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
        return ATA_DEFER_PORT;
 }
 
-static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs)
+static void mv_config_fbs(struct ata_port *ap, int want_ncq, int want_fbs)
 {
-       u32 new_fiscfg, old_fiscfg;
-       u32 new_ltmode, old_ltmode;
-       u32 new_haltcond, old_haltcond;
+       struct mv_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio;
 
-       old_fiscfg   = readl(port_mmio + FISCFG_OFS);
-       old_ltmode   = readl(port_mmio + LTMODE_OFS);
-       old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+       u32 fiscfg,   *old_fiscfg   = &pp->cached.fiscfg;
+       u32 ltmode,   *old_ltmode   = &pp->cached.ltmode;
+       u32 haltcond, *old_haltcond = &pp->cached.haltcond;
 
-       new_fiscfg   = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
-       new_ltmode   = old_ltmode & ~LTMODE_BIT8;
-       new_haltcond = old_haltcond | EDMA_ERR_DEV;
+       ltmode   = *old_ltmode & ~LTMODE_BIT8;
+       haltcond = *old_haltcond | EDMA_ERR_DEV;
 
        if (want_fbs) {
-               new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC;
-               new_ltmode = old_ltmode | LTMODE_BIT8;
+               fiscfg = *old_fiscfg | FISCFG_SINGLE_SYNC;
+               ltmode = *old_ltmode | LTMODE_BIT8;
                if (want_ncq)
-                       new_haltcond &= ~EDMA_ERR_DEV;
+                       haltcond &= ~EDMA_ERR_DEV;
                else
-                       new_fiscfg |=  FISCFG_WAIT_DEV_ERR;
+                       fiscfg |=  FISCFG_WAIT_DEV_ERR;
+       } else {
+               fiscfg = *old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
        }
 
-       if (new_fiscfg != old_fiscfg)
-               writelfl(new_fiscfg, port_mmio + FISCFG_OFS);
-       if (new_ltmode != old_ltmode)
-               writelfl(new_ltmode, port_mmio + LTMODE_OFS);
-       if (new_haltcond != old_haltcond)
-               writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS);
+       port_mmio = mv_ap_base(ap);
+       mv_write_cached_reg(port_mmio + FISCFG_OFS, old_fiscfg, fiscfg);
+       mv_write_cached_reg(port_mmio + LTMODE_OFS, old_ltmode, ltmode);
+       mv_write_cached_reg(port_mmio + EDMA_HALTCOND_OFS, old_haltcond, haltcond);
 }
 
 static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
@@ -1205,6 +1388,85 @@ static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
                writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS);
 }
 
+/**
+ *     mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma
+ *     @ap: Port being initialized
+ *
+ *     There are two DMA modes on these chips:  basic DMA, and EDMA.
+ *
+ *     Bit-0 of the "EDMA RESERVED" register enables/disables use
+ *     of basic DMA on the GEN_IIE versions of the chips.
+ *
+ *     This bit survives EDMA resets, and must be set for basic DMA
+ *     to function, and should be cleared when EDMA is active.
+ */
+static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma)
+{
+       struct mv_port_priv *pp = ap->private_data;
+       u32 new, *old = &pp->cached.unknown_rsvd;
+
+       if (enable_bmdma)
+               new = *old | 1;
+       else
+               new = *old & ~1;
+       mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new);
+}
+
+/*
+ * SOC chips have an issue whereby the HDD LEDs don't always blink
+ * during I/O when NCQ is enabled. Enabling a special "LED blink" mode
+ * of the SOC takes care of it, generating a steady blink rate when
+ * any drive on the chip is active.
+ *
+ * Unfortunately, the blink mode is a global hardware setting for the SOC,
+ * so we must use it whenever at least one port on the SOC has NCQ enabled.
+ *
+ * We turn "LED blink" off when NCQ is not in use anywhere, because the normal
+ * LED operation works then, and provides better (more accurate) feedback.
+ *
+ * Note that this code assumes that an SOC never has more than one HC onboard.
+ */
+static void mv_soc_led_blink_enable(struct ata_port *ap)
+{
+       struct ata_host *host = ap->host;
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *hc_mmio;
+       u32 led_ctrl;
+
+       if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)
+               return;
+       hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN;
+       hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+       led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
+       writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
+}
+
+static void mv_soc_led_blink_disable(struct ata_port *ap)
+{
+       struct ata_host *host = ap->host;
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *hc_mmio;
+       u32 led_ctrl;
+       unsigned int port;
+
+       if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN))
+               return;
+
+       /* disable led-blink only if no ports are using NCQ */
+       for (port = 0; port < hpriv->n_ports; port++) {
+               struct ata_port *this_ap = host->ports[port];
+               struct mv_port_priv *pp = this_ap->private_data;
+
+               if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
+                       return;
+       }
+
+       hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN;
+       hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+       led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
+       writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
+}
+
 static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
 {
        u32 cfg;
@@ -1214,7 +1476,8 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
 
        /* set up non-NCQ EDMA configuration */
        cfg = EDMA_CFG_Q_DEPTH;         /* always 0x1f for *all* chips */
-       pp->pp_flags &= ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN);
+       pp->pp_flags &=
+         ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
        if (IS_GEN_I(hpriv))
                cfg |= (1 << 8);        /* enab config burst size mask */
@@ -1235,7 +1498,7 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
                 */
                want_fbs &= want_ncq;
 
-               mv_config_fbs(port_mmio, want_ncq, want_fbs);
+               mv_config_fbs(ap, want_ncq, want_fbs);
 
                if (want_fbs) {
                        pp->pp_flags |= MV_PP_FLAG_FBS_EN;
@@ -1250,6 +1513,14 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
                }
                if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
                        cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
+               mv_bmdma_enable_iie(ap, !want_edma);
+
+               if (IS_SOC(hpriv)) {
+                       if (want_ncq)
+                               mv_soc_led_blink_enable(ap);
+                       else
+                               mv_soc_led_blink_disable(ap);
+               }
        }
 
        if (want_ncq) {
@@ -1339,6 +1610,7 @@ static int mv_port_start(struct ata_port *ap)
                        pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
                }
        }
+       mv_save_cached_regs(ap);
        mv_edma_cfg(ap, 0, 0);
        return 0;
 
@@ -1416,26 +1688,6 @@ static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
        *cmdw = cpu_to_le16(tmp);
 }
 
-/**
- *     mv_mode_filter - Allow ATAPI DMA only on GenII chips.
- *     @dev: device whose xfer modes are being configured.
- *
- *     Only the GenII hardware can use DMA with ATAPI drives.
- */
-static unsigned long mv_mode_filter(struct ata_device *adev,
-                                   unsigned long xfer_mask)
-{
-       if (adev->class == ATA_DEV_ATAPI) {
-               struct mv_host_priv *hpriv = adev->link->ap->host->private_data;
-               if (!IS_GEN_II(hpriv)) {
-                       xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
-                       ata_dev_printk(adev, KERN_INFO,
-                               "ATAPI DMA not supported on this chipset\n");
-               }
-       }
-       return xfer_mask;
-}
-
 /**
  *     mv_sff_irq_clear - Clear hardware interrupt after DMA.
  *     @ap: Port associated with this ATA transaction.
@@ -1738,6 +1990,132 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        mv_fill_sg(qc);
 }
 
+/**
+ *     mv_sff_check_status - fetch device status, if valid
+ *     @ap: ATA port to fetch status from
+ *
+ *     When using command issue via mv_qc_issue_fis(),
+ *     the initial ATA_BUSY state does not show up in the
+ *     ATA status (shadow) register.  This can confuse libata!
+ *
+ *     So we have a hook here to fake ATA_BUSY for that situation,
+ *     until the first time a BUSY, DRQ, or ERR bit is seen.
+ *
+ *     The rest of the time, it simply returns the ATA status register.
+ */
+static u8 mv_sff_check_status(struct ata_port *ap)
+{
+       u8 stat = ioread8(ap->ioaddr.status_addr);
+       struct mv_port_priv *pp = ap->private_data;
+
+       if (pp->pp_flags & MV_PP_FLAG_FAKE_ATA_BUSY) {
+               if (stat & (ATA_BUSY | ATA_DRQ | ATA_ERR))
+                       pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY;
+               else
+                       stat = ATA_BUSY;
+       }
+       return stat;
+}
+
+/**
+ *     mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register
+ *     @fis: fis to be sent
+ *     @nwords: number of 32-bit words in the fis
+ */
+static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       u32 ifctl, old_ifctl, ifstat;
+       int i, timeout = 200, final_word = nwords - 1;
+
+       /* Initiate FIS transmission mode */
+       old_ifctl = readl(port_mmio + SATA_IFCTL_OFS);
+       ifctl = 0x100 | (old_ifctl & 0xf);
+       writelfl(ifctl, port_mmio + SATA_IFCTL_OFS);
+
+       /* Send all words of the FIS except for the final word */
+       for (i = 0; i < final_word; ++i)
+               writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+       /* Flag end-of-transmission, and then send the final word */
+       writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL_OFS);
+       writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+       /*
+        * Wait for FIS transmission to complete.
+        * This typically takes just a single iteration.
+        */
+       do {
+               ifstat = readl(port_mmio + SATA_IFSTAT_OFS);
+       } while (!(ifstat & 0x1000) && --timeout);
+
+       /* Restore original port configuration */
+       writelfl(old_ifctl, port_mmio + SATA_IFCTL_OFS);
+
+       /* See if it worked */
+       if ((ifstat & 0x3000) != 0x1000) {
+               ata_port_printk(ap, KERN_WARNING,
+                               "%s transmission error, ifstat=%08x\n",
+                               __func__, ifstat);
+               return AC_ERR_OTHER;
+       }
+       return 0;
+}
+
+/**
+ *     mv_qc_issue_fis - Issue a command directly as a FIS
+ *     @qc: queued command to start
+ *
+ *     Note that the ATA shadow registers are not updated
+ *     after command issue, so the device will appear "READY"
+ *     if polled, even while it is BUSY processing the command.
+ *
+ *     So we use a status hook to fake ATA_BUSY until the drive changes state.
+ *
+ *     Note: we don't get updated shadow regs on *completion*
+ *     of non-data commands. So avoid sending them via this function,
+ *     as they will appear to have completed immediately.
+ *
+ *     GEN_IIE has special registers that we could get the result tf from,
+ *     but earlier chipsets do not.  For now, we ignore those registers.
+ */
+static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct mv_port_priv *pp = ap->private_data;
+       struct ata_link *link = qc->dev->link;
+       u32 fis[5];
+       int err = 0;
+
+       ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
+       err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0]));
+       if (err)
+               return err;
+
+       switch (qc->tf.protocol) {
+       case ATAPI_PROT_PIO:
+               pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+               /* fall through */
+       case ATAPI_PROT_NODATA:
+               ap->hsm_task_state = HSM_ST_FIRST;
+               break;
+       case ATA_PROT_PIO:
+               pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+               if (qc->tf.flags & ATA_TFLAG_WRITE)
+                       ap->hsm_task_state = HSM_ST_FIRST;
+               else
+                       ap->hsm_task_state = HSM_ST;
+               break;
+       default:
+               ap->hsm_task_state = HSM_ST_LAST;
+               break;
+       }
+
+       if (qc->tf.flags & ATA_TFLAG_POLLING)
+               ata_pio_queue_task(ap, qc, 0);
+       return 0;
+}
+
 /**
  *      mv_qc_issue - Initiate a command to the host
  *      @qc: queued command to start
@@ -1757,7 +2135,9 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
        u32 in_index;
-       unsigned int port_irqs = DONE_IRQ | ERR_IRQ;
+       unsigned int port_irqs;
+
+       pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY; /* paranoia */
 
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
@@ -1790,20 +2170,45 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                                        "this may fail due to h/w errata\n");
                }
                /* drop through */
+       case ATA_PROT_NODATA:
        case ATAPI_PROT_PIO:
-               port_irqs = ERR_IRQ;    /* leave DONE_IRQ masked for PIO */
-               /* drop through */
-       default:
+       case ATAPI_PROT_NODATA:
+               if (ap->flags & ATA_FLAG_PIO_POLLING)
+                       qc->tf.flags |= ATA_TFLAG_POLLING;
+               break;
+       }
+
+       if (qc->tf.flags & ATA_TFLAG_POLLING)
+               port_irqs = ERR_IRQ;    /* mask device interrupt when polling */
+       else
+               port_irqs = ERR_IRQ | DONE_IRQ; /* unmask all interrupts */
+
+       /*
+        * We're about to send a non-EDMA capable command to the
+        * port.  Turn off EDMA so there won't be problems accessing
+        * shadow block, etc registers.
+        */
+       mv_stop_edma(ap);
+       mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
+       mv_pmp_select(ap, qc->dev->link->pmp);
+
+       if (qc->tf.command == ATA_CMD_READ_LOG_EXT) {
+               struct mv_host_priv *hpriv = ap->host->private_data;
                /*
-                * We're about to send a non-EDMA capable command to the
-                * port.  Turn off EDMA so there won't be problems accessing
-                * shadow block, etc registers.
+                * Workaround for 88SX60x1 FEr SATA#25 (part 2).
+                *
+                * After any NCQ error, the READ_LOG_EXT command
+                * from libata-eh *must* use mv_qc_issue_fis().
+                * Otherwise it might fail, due to chip errata.
+                *
+                * Rather than special-case it, we'll just *always*
+                * use this method here for READ_LOG_EXT, making for
+                * easier testing.
                 */
-               mv_stop_edma(ap);
-               mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
-               mv_pmp_select(ap, qc->dev->link->pmp);
-               return ata_sff_qc_issue(qc);
+               if (IS_GEN_II(hpriv))
+                       return mv_qc_issue_fis(qc);
        }
+       return ata_sff_qc_issue(qc);
 }
 
 static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
@@ -2288,6 +2693,10 @@ static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
        void __iomem *mmio = hpriv->base, *hc_mmio;
        unsigned int handled = 0, port;
 
+       /* If asserted, clear the "all ports" IRQ coalescing bit */
+       if (main_irq_cause & ALL_PORTS_COAL_DONE)
+               writel(~ALL_PORTS_COAL_IRQ, mmio + MV_IRQ_COAL_CAUSE);
+
        for (port = 0; port < hpriv->n_ports; port++) {
                struct ata_port *ap = host->ports[port];
                unsigned int p, shift, hardport, port_cause;
@@ -2320,6 +2729,8 @@ static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
                         * to ack (only) those ports via hc_irq_cause.
                         */
                        ack_irqs = 0;
+                       if (hc_cause & PORTS_0_3_COAL_DONE)
+                               ack_irqs = HC_COAL_IRQ;
                        for (p = 0; p < MV_PORTS_PER_HC; ++p) {
                                if ((port + p) >= hpriv->n_ports)
                                        break;
@@ -2408,7 +2819,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
 
        /* for MSI:  block new interrupts while in here */
        if (using_msi)
-               writel(0, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(0, hpriv);
 
        main_irq_cause = readl(hpriv->main_irq_cause_addr);
        pending_irqs   = main_irq_cause & hpriv->main_irq_mask;
@@ -2425,7 +2836,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
 
        /* for MSI: unmask; interrupt cause bits will retrigger now */
        if (using_msi)
-               writel(hpriv->main_irq_mask, hpriv->main_irq_mask_addr);
+               mv_write_main_irq_mask(hpriv->main_irq_mask, hpriv);
 
        spin_unlock(&host->lock);
 
@@ -2978,6 +3389,8 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
 
        mv_reset_channel(hpriv, mmio, ap->port_no);
        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+       pp->pp_flags &=
+         ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
        /* Workaround for errata FEr SATA#10 (part 2) */
        do {
@@ -2997,6 +3410,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
                                extra = HZ; /* only extend it once, max */
                }
        } while (sstatus != 0x0 && sstatus != 0x113 && sstatus != 0x123);
+       mv_save_cached_regs(ap);
        mv_edma_cfg(ap, 0, 0);
 
        return rc;
@@ -3331,6 +3745,8 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
         * The per-port interrupts get done later as ports are set up.
         */
        mv_set_main_irq_mask(host, 0, PCI_ERR);
+       mv_set_irq_coalescing(host, irq_coalescing_io_count,
+                                   irq_coalescing_usecs);
 done:
        return rc;
 }
@@ -3492,12 +3908,6 @@ static struct pci_driver mv_pci_driver = {
        .remove                 = ata_pci_remove_one,
 };
 
-/*
- * module options
- */
-static int msi;              /* Use PCI msi; either zero (off, default) or non-zero */
-
-
 /* move to PCI layer or libata core? */
 static int pci_go_64(struct pci_dev *pdev)
 {
@@ -3679,10 +4089,5 @@ MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:" DRV_NAME);
 
-#ifdef CONFIG_PCI
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
-#endif
-
 module_init(mv_init);
 module_exit(mv_exit);