]> err.no Git - linux-2.6/blobdiff - drivers/ata/ahci.c
libata: eliminate the home grown dma padding in favour of
[linux-2.6] / drivers / ata / ahci.c
index 49761bc12cf26b719337c8264512194000815d96..3c06e457b4dc86929949e700292fd3149fff79fd 100644 (file)
@@ -475,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,
@@ -597,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
@@ -619,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.
         */
@@ -660,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;
                }
        }
@@ -1043,13 +1058,10 @@ static int ahci_reset_controller(struct ata_host *host)
        /* 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 */
@@ -1068,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);
@@ -1964,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)
@@ -2186,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");
 
@@ -2240,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);