]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/ahci.c
copyright owner and author clean up for intel iommu and related files
[linux-2.6-omap-h63xx.git] / drivers / ata / ahci.c
index 4688dbf2d1110d7b31ab4809e1de621721fd0456..6dd12f7019a006cefc64a7a5b1b10d3b7a747160 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 {
@@ -473,6 +475,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
        { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
+       { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+       { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -595,6 +599,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
        return __ahci_port_base(ap->host, ap->port_no);
 }
 
+static void ahci_enable_ahci(void __iomem *mmio)
+{
+       u32 tmp;
+
+       /* turn on AHCI_EN */
+       tmp = readl(mmio + HOST_CTL);
+       if (!(tmp & HOST_AHCI_EN)) {
+               tmp |= HOST_AHCI_EN;
+               writel(tmp, mmio + HOST_CTL);
+               tmp = readl(mmio + HOST_CTL);   /* flush && sanity check */
+               WARN_ON(!(tmp & HOST_AHCI_EN));
+       }
+}
+
 /**
  *     ahci_save_initial_config - Save and fixup initial config values
  *     @pdev: target PCI device
@@ -617,6 +635,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        u32 cap, port_map;
        int i;
 
+       /* make sure AHCI mode is enabled before accessing CAP */
+       ahci_enable_ahci(mmio);
+
        /* Values prefixed with saved_ are written back to host after
         * reset.  Values without are used for driver operation.
         */
@@ -658,24 +679,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
 
        /* cross check port_map and cap.n_ports */
        if (port_map) {
-               u32 tmp_port_map = port_map;
-               int n_ports = ahci_nr_ports(cap);
+               int map_ports = 0;
 
-               for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
-                       if (tmp_port_map & (1 << i)) {
-                               n_ports--;
-                               tmp_port_map &= ~(1 << i);
-                       }
-               }
+               for (i = 0; i < AHCI_MAX_PORTS; i++)
+                       if (port_map & (1 << i))
+                               map_ports++;
 
-               /* If n_ports and port_map are inconsistent, whine and
-                * clear port_map and let it be generated from n_ports.
+               /* If PI has more ports than n_ports, whine, clear
+                * port_map and let it be generated from n_ports.
                 */
-               if (n_ports || tmp_port_map) {
+               if (map_ports > ahci_nr_ports(cap)) {
                        dev_printk(KERN_WARNING, &pdev->dev,
-                                  "nr_ports (%u) and implemented port map "
-                                  "(0x%x) don't match, using nr_ports\n",
-                                  ahci_nr_ports(cap), port_map);
+                                  "implemented port map (0x%x) contains more "
+                                  "ports than nr_ports (%u), using nr_ports\n",
+                                  port_map, ahci_nr_ports(cap));
                        port_map = 0;
                }
        }
@@ -1034,19 +1051,17 @@ 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;
 
        /* we must be in AHCI mode, before using anything
         * AHCI-specific, such as HOST_RESET.
         */
-       tmp = readl(mmio + HOST_CTL);
-       if (!(tmp & HOST_AHCI_EN)) {
-               tmp |= HOST_AHCI_EN;
-               writel(tmp, mmio + HOST_CTL);
-       }
+       ahci_enable_ahci(mmio);
 
        /* global controller reset */
+       tmp = readl(mmio + HOST_CTL);
        if ((tmp & HOST_RESET) == 0) {
                writel(tmp | HOST_RESET, mmio + HOST_CTL);
                readl(mmio + HOST_CTL); /* flush */
@@ -1065,8 +1080,7 @@ static int ahci_reset_controller(struct ata_host *host)
        }
 
        /* turn on AHCI mode */
-       writel(HOST_AHCI_EN, mmio + HOST_CTL);
-       (void) readl(mmio + HOST_CTL);  /* flush */
+       ahci_enable_ahci(mmio);
 
        /* some registers might be cleared on reset.  restore initial values */
        ahci_restore_initial_config(host);
@@ -1076,8 +1090,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;
@@ -1271,9 +1287,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);
 
@@ -1478,35 +1494,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 */
@@ -1638,7 +1650,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);
@@ -1696,80 +1708,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)
@@ -1988,7 +1932,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
        void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 ctl;
 
-       if (mesg.event == PM_EVENT_SUSPEND) {
+       if (mesg.event & PM_EVENT_SLEEP) {
                /* AHCI spec rev1.1 section 8.3.3:
                 * Software must disable interrupts prior to requesting a
                 * transition of the HBA to D3 state.
@@ -2031,16 +1975,11 @@ static int ahci_port_start(struct ata_port *ap)
        struct ahci_port_priv *pp;
        void *mem;
        dma_addr_t mem_dma;
-       int rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
        if (!pp)
                return -ENOMEM;
 
-       rc = ata_pad_alloc(ap, dev);
-       if (rc)
-               return rc;
-
        mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
                                  GFP_KERNEL);
        if (!mem)
@@ -2253,7 +2192,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
        struct ata_host *host;
-       int i, rc;
+       int n_ports, i, rc;
 
        VPRINTK("ENTER\n");
 
@@ -2273,6 +2212,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;
@@ -2291,7 +2246,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (hpriv->cap & HOST_CAP_PMP)
                pi.flags |= ATA_FLAG_PMP;
 
-       host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+       /* CAP.NP sometimes indicate the index of the last enabled
+        * port, at other times, that of the last possible port, so
+        * determining the maximum port number requires looking at
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
        if (!host)
                return -ENOMEM;
        host->iomap = pcim_iomap_table(pdev);