]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/ahci.c
libata: factor out ata_pci_activate_sff_host() from ata_pci_one()
[linux-2.6-omap-h63xx.git] / drivers / ata / ahci.c
index ed9b407e42d4ec3f7112a4b763b217085511e5d1..49761bc12cf26b719337c8264512194000815d96 100644 (file)
@@ -193,21 +193,23 @@ enum {
                                          ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
                                          ATA_FLAG_IPM,
        AHCI_LFLAG_COMMON               = ATA_LFLAG_SKIP_D2H_BSY,
+
+       ICH_MAP                         = 0x90, /* ICH MAP register */
 };
 
 struct ahci_cmd_hdr {
-       u32                     opts;
-       u32                     status;
-       u32                     tbl_addr;
-       u32                     tbl_addr_hi;
-       u32                     reserved[4];
+       __le32                  opts;
+       __le32                  status;
+       __le32                  tbl_addr;
+       __le32                  tbl_addr_hi;
+       __le32                  reserved[4];
 };
 
 struct ahci_sg {
-       u32                     addr;
-       u32                     addr_hi;
-       u32                     reserved;
-       u32                     flags_size;
+       __le32                  addr;
+       __le32                  addr_hi;
+       __le32                  reserved;
+       __le32                  flags_size;
 };
 
 struct ahci_host_priv {
@@ -536,6 +538,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },            /* MCP77 */
        { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },            /* MCP77 */
        { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },            /* MCP79 */
        { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },            /* MCP79 */
        { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },            /* MCP79 */
        { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },            /* MCP79 */
@@ -1030,6 +1036,7 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 static int ahci_reset_controller(struct ata_host *host)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 tmp;
 
@@ -1072,8 +1079,10 @@ static int ahci_reset_controller(struct ata_host *host)
 
                /* configure PCS */
                pci_read_config_word(pdev, 0x92, &tmp16);
-               tmp16 |= 0xf;
-               pci_write_config_word(pdev, 0x92, tmp16);
+               if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
+                       tmp16 |= hpriv->port_map;
+                       pci_write_config_word(pdev, 0x92, tmp16);
+               }
        }
 
        return 0;
@@ -1267,9 +1276,9 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
        rc = ahci_kick_engine(ap, 1);
-       if (rc)
+       if (rc && rc != -EOPNOTSUPP)
                ata_link_printk(link, KERN_WARNING,
-                               "failed to reset engine (errno=%d)", rc);
+                               "failed to reset engine (errno=%d)\n", rc);
 
        ata_tf_init(link->device, &tf);
 
@@ -1474,35 +1483,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
 {
        struct scatterlist *sg;
-       struct ahci_sg *ahci_sg;
-       unsigned int n_sg = 0;
+       struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+       unsigned int si;
 
        VPRINTK("ENTER\n");
 
        /*
         * Next, the S/G list.
         */
-       ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
 
-               ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
-               ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
-               ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
-
-               ahci_sg++;
-               n_sg++;
+               ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+               ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+               ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
        }
 
-       return n_sg;
+       return si;
 }
 
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct ahci_port_priv *pp = ap->private_data;
-       int is_atapi = is_atapi_taskfile(&qc->tf);
+       int is_atapi = ata_is_atapi(qc->tf.protocol);
        void *cmd_tbl;
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
@@ -1634,7 +1639,7 @@ static void ahci_port_intr(struct ata_port *ap)
        struct ahci_host_priv *hpriv = ap->host->private_data;
        int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
        u32 status, qc_active;
-       int rc, known_irq = 0;
+       int rc;
 
        status = readl(port_mmio + PORT_IRQ_STAT);
        writel(status, port_mmio + PORT_IRQ_STAT);
@@ -1692,80 +1697,12 @@ static void ahci_port_intr(struct ata_port *ap)
 
        rc = ata_qc_complete_multiple(ap, qc_active, NULL);
 
-       /* If resetting, spurious or invalid completions are expected,
-        * return unconditionally.
-        */
-       if (resetting)
-               return;
-
-       if (rc > 0)
-               return;
-       if (rc < 0) {
+       /* while resetting, invalid completions are expected */
+       if (unlikely(rc < 0 && !resetting)) {
                ehi->err_mask |= AC_ERR_HSM;
                ehi->action |= ATA_EH_SOFTRESET;
                ata_port_freeze(ap);
-               return;
-       }
-
-       /* hmmm... a spurious interrupt */
-
-       /* if !NCQ, ignore.  No modern ATA device has broken HSM
-        * implementation for non-NCQ commands.
-        */
-       if (!ap->link.sactive)
-               return;
-
-       if (status & PORT_IRQ_D2H_REG_FIS) {
-               if (!pp->ncq_saw_d2h)
-                       ata_port_printk(ap, KERN_INFO,
-                               "D2H reg with I during NCQ, "
-                               "this message won't be printed again\n");
-               pp->ncq_saw_d2h = 1;
-               known_irq = 1;
-       }
-
-       if (status & PORT_IRQ_DMAS_FIS) {
-               if (!pp->ncq_saw_dmas)
-                       ata_port_printk(ap, KERN_INFO,
-                               "DMAS FIS during NCQ, "
-                               "this message won't be printed again\n");
-               pp->ncq_saw_dmas = 1;
-               known_irq = 1;
-       }
-
-       if (status & PORT_IRQ_SDB_FIS) {
-               const __le32 *f = pp->rx_fis + RX_FIS_SDB;
-
-               if (le32_to_cpu(f[1])) {
-                       /* SDB FIS containing spurious completions
-                        * might be dangerous, whine and fail commands
-                        * with HSM violation.  EH will turn off NCQ
-                        * after several such failures.
-                        */
-                       ata_ehi_push_desc(ehi,
-                               "spurious completions during NCQ "
-                               "issue=0x%x SAct=0x%x FIS=%08x:%08x",
-                               readl(port_mmio + PORT_CMD_ISSUE),
-                               readl(port_mmio + PORT_SCR_ACT),
-                               le32_to_cpu(f[0]), le32_to_cpu(f[1]));
-                       ehi->err_mask |= AC_ERR_HSM;
-                       ehi->action |= ATA_EH_SOFTRESET;
-                       ata_port_freeze(ap);
-               } else {
-                       if (!pp->ncq_saw_sdb)
-                               ata_port_printk(ap, KERN_INFO,
-                                       "spurious SDB FIS %08x:%08x during NCQ, "
-                                       "this message won't be printed again\n",
-                                       le32_to_cpu(f[0]), le32_to_cpu(f[1]));
-                       pp->ncq_saw_sdb = 1;
-               }
-               known_irq = 1;
        }
-
-       if (!known_irq)
-               ata_port_printk(ap, KERN_INFO, "spurious interrupt "
-                               "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
-                               status, ap->link.active_tag, ap->link.sactive);
 }
 
 static void ahci_irq_clear(struct ata_port *ap)
@@ -2269,6 +2206,22 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+           (pdev->device == 0x2652 || pdev->device == 0x2653)) {
+               u8 map;
+
+               /* ICH6s share the same PCI ID for both piix and ahci
+                * modes.  Enabling ahci mode while MAP indicates
+                * combined mode is a bad idea.  Yield to ata_piix.
+                */
+               pci_read_config_byte(pdev, ICH_MAP, &map);
+               if (map & 0x3) {
+                       dev_printk(KERN_INFO, &pdev->dev, "controller is in "
+                                  "combined mode, can't enable AHCI mode\n");
+                       return -ENODEV;
+               }
+       }
+
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;