[PATCH] ahci: update ahci-vt8251 reset sequence
[deliverable/linux.git] / drivers / ata / ahci.c
index 1aabc81d82f1dcc96a3dd8929f8b59d68fa6b3e3..8a1f4f059a43c9e18aef27df6c0c75c811eaf79c 100644 (file)
@@ -78,6 +78,7 @@ enum {
 
        board_ahci              = 0,
        board_ahci_vt8251       = 1,
+       board_ahci_ign_iferr    = 2,
 
        /* global controller registers */
        HOST_CAP                = 0x00, /* host capabilities */
@@ -166,8 +167,8 @@ enum {
        AHCI_FLAG_MSI           = (1 << 0),
 
        /* ap->flags bits */
-       AHCI_FLAG_RESET_NEEDS_CLO       = (1 << 24),
-       AHCI_FLAG_NO_NCQ                = (1 << 25),
+       AHCI_FLAG_NO_NCQ                = (1 << 24),
+       AHCI_FLAG_IGN_IRQ_IF_ERR        = (1 << 25), /* ignore IRQ_IF_ERR */
 };
 
 struct ahci_cmd_hdr {
@@ -204,7 +205,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -214,6 +215,7 @@ static u8 ahci_check_status(struct ata_port *ap);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
 static void ahci_error_handler(struct ata_port *ap);
+static void ahci_vt8251_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
 static int ahci_port_resume(struct ata_port *ap);
@@ -273,6 +275,37 @@ static const struct ata_port_operations ahci_ops = {
        .port_stop              = ahci_port_stop,
 };
 
+static const struct ata_port_operations ahci_vt8251_ops = {
+       .port_disable           = ata_port_disable,
+
+       .check_status           = ahci_check_status,
+       .check_altstatus        = ahci_check_status,
+       .dev_select             = ata_noop_dev_select,
+
+       .tf_read                = ahci_tf_read,
+
+       .qc_prep                = ahci_qc_prep,
+       .qc_issue               = ahci_qc_issue,
+
+       .irq_handler            = ahci_interrupt,
+       .irq_clear              = ahci_irq_clear,
+
+       .scr_read               = ahci_scr_read,
+       .scr_write              = ahci_scr_write,
+
+       .freeze                 = ahci_freeze,
+       .thaw                   = ahci_thaw,
+
+       .error_handler          = ahci_vt8251_error_handler,
+       .post_internal_cmd      = ahci_post_internal_cmd,
+
+       .port_suspend           = ahci_port_suspend,
+       .port_resume            = ahci_port_resume,
+
+       .port_start             = ahci_port_start,
+       .port_stop              = ahci_port_stop,
+};
+
 static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci */
        {
@@ -290,7 +323,18 @@ static const struct ata_port_info ahci_port_info[] = {
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
                                  ATA_FLAG_SKIP_D2H_BSY |
-                                 AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
+                                 ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &ahci_vt8251_ops,
+       },
+       /* board_ahci_ign_iferr */
+       {
+               .sht            = &ahci_sht,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                 ATA_FLAG_SKIP_D2H_BSY |
+                                 AHCI_FLAG_IGN_IRQ_IF_ERR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
@@ -299,76 +343,65 @@ static const struct ata_port_info ahci_port_info[] = {
 
 static const struct pci_device_id ahci_pci_tbl[] = {
        /* Intel */
-       { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH6 */
-       { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH6M */
-       { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH7 */
-       { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH7M */
-       { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH7R */
-       { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ULi M5288 */
-       { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ESB2 */
-       { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ESB2 */
-       { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ESB2 */
-       { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH7-M DH */
-       { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8 */
-       { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8 */
-       { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8 */
-       { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8M */
-       { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8M */
+       { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
+       { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
+       { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
+       { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
+       { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
+       { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+       { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+       { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
 
        /* JMicron */
-       { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* JMicron JMB360 */
-       { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* JMicron JMB361 */
-       { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* JMicron JMB363 */
-       { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* JMicron JMB365 */
-       { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* JMicron JMB366 */
+       { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */
+       { PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */
+       { PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */
+       { PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */
+       { PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */
 
        /* ATI */
-       { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ATI SB600 non-raid */
-       { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ATI SB600 raid */
+       { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
+       { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
 
        /* VIA */
-       { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci_vt8251 }, /* VIA VT8251 */
+       { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
 
        /* NVIDIA */
-       { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci },         /* MCP65 */
-       { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci },         /* MCP65 */
-       { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci },         /* MCP65 */
-       { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci },         /* MCP65 */
+       { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },            /* MCP65 */
+       { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },            /* MCP65 */
+       { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },            /* MCP65 */
+       { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },            /* MCP65 */
+       { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },            /* MCP67 */
+       { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },            /* MCP67 */
 
        /* SiS */
-       { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* SiS 966 */
-       { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* SiS 966 */
-       { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* SiS 968 */
+       { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+       { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
+       { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
 
        { }     /* terminate list */
 };
@@ -727,17 +760,6 @@ static int ahci_clo(struct ata_port *ap)
        return 0;
 }
 
-static int ahci_prereset(struct ata_port *ap)
-{
-       if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
-           (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
-               /* ATA_BUSY hasn't cleared, so send a CLO */
-               ahci_clo(ap);
-       }
-
-       return ata_std_prereset(ap);
-}
-
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
        struct ahci_port_priv *pp = ap->private_data;
@@ -766,8 +788,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* check BUSY/DRQ, perform Command List Override if necessary */
-       ahci_tf_read(ap, &tf);
-       if (tf.command & (ATA_BUSY | ATA_DRQ)) {
+       if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
                rc = ahci_clo(ap);
 
                if (rc == -EOPNOTSUPP) {
@@ -876,6 +897,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
        return rc;
 }
 
+static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
+{
+       void __iomem *mmio = ap->host->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(port_mmio);
+
+       rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
+
+       /* vt8251 needs SError cleared for the port to operate */
+       ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+
+       ahci_start_engine(port_mmio);
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+
+       /* vt8251 doesn't clear BSY on signature FIS reception,
+        * request follow-up softreset.
+        */
+       return rc ?: -EAGAIN;
+}
+
 static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 {
        void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -992,6 +1038,10 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        /* analyze @irq_stat */
        ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
 
+       /* some controllers set IRQ_IF_ERR on device errors, ignore it */
+       if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+               irq_stat &= ~PORT_IRQ_IF_ERR;
+
        if (irq_stat & PORT_IRQ_TF_ERR)
                err_mask |= AC_ERR_DEV;
 
@@ -1071,7 +1121,7 @@ static void ahci_host_intr(struct ata_port *ap)
        /* hmmm... a spurious interupt */
 
        /* some devices send D2H reg with I bit set during NCQ command phase */
-       if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+       if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS))
                return;
 
        /* ignore interim PIO setup fis interrupts */
@@ -1089,7 +1139,7 @@ static void ahci_irq_clear(struct ata_port *ap)
        /* TODO */
 }
 
-static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
        struct ahci_host_priv *hpriv;
@@ -1191,7 +1241,23 @@ static void ahci_error_handler(struct ata_port *ap)
        }
 
        /* perform recovery */
-       ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
+       ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
+                 ahci_postreset);
+}
+
+static void ahci_vt8251_error_handler(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->host->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+       if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+               /* restart engine */
+               ahci_stop_engine(port_mmio);
+               ahci_start_engine(port_mmio);
+       }
+
+       /* perform recovery */
+       ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
                  ahci_postreset);
 }
 
This page took 0.02798 seconds and 5 git commands to generate.