Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[sfrench/cifs-2.6.git] / drivers / ata / libata-sff.c
index e35d13466c69092c68e822f4cb150b6f492cefab..8023167bbbeb68623fd9939887010fb74362cb70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *  libata-sff.c - helper library for PCI IDE BMDMA
  *
  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
  *                 Please ALWAYS copy linux-ide@vger.kernel.org
@@ -80,25 +80,25 @@ u8 ata_dummy_irq_on (struct ata_port *ap)   { return 0; }
 u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
 {
        unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-       u8 host_stat, post_stat, status;
+       u8 host_stat = 0, post_stat = 0, status;
 
        status = ata_busy_wait(ap, bits, 1000);
        if (status & bits)
                if (ata_msg_err(ap))
                        printk(KERN_ERR "abnormal status 0x%X\n", status);
 
-       /* get controller status; clear intr, err bits */
-       host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-       iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-                ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
-       post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+       if (ap->ioaddr.bmdma_addr) {
+               /* get controller status; clear intr, err bits */
+               host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+               iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+                        ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 
+               post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+       }
        if (ata_msg_intr(ap))
                printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
                        __FUNCTION__,
                        host_stat, post_stat, status);
-
        return status;
 }
 
@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
                tf->hob_lbal = ioread8(ioaddr->lbal_addr);
                tf->hob_lbam = ioread8(ioaddr->lbam_addr);
                tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+               iowrite8(tf->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = tf->ctl;
        }
 }
 
@@ -295,7 +297,7 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
        dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
        iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 
-       /* Strictly, one may wish to issue a readb() here, to
+       /* Strictly, one may wish to issue an ioread8() here, to
         * flush the mmio write.  However, control also passes
         * to the hardware at this point, and it will interrupt
         * us when we are to resume control.  So, in effect,
@@ -305,6 +307,9 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
         * is expected, so I think it is best to not add a readb()
         * without first all the MMIO ATA cards/mobos.
         * Or maybe I'm just being paranoid.
+        *
+        * FIXME: The posting of this write means I/O starts are
+        * unneccessarily delayed for MMIO
         */
 }
 
@@ -516,6 +521,27 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
                ata_bmdma_stop(qc);
 }
 
+/**
+ *     ata_sff_port_start - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.  Allocates space for PRD table if the device
+ *     is DMA capable SFF.
+ *
+ *     May be used as the port_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+int ata_sff_port_start(struct ata_port *ap)
+{
+       if (ap->ioaddr.bmdma_addr)
+               return ata_port_start(ap);
+       return 0;
+}
+
 #ifdef CONFIG_PCI
 
 static int ata_resources_present(struct pci_dev *pdev, int port)
@@ -550,6 +576,10 @@ int ata_pci_init_bmdma(struct ata_host *host)
        struct pci_dev *pdev = to_pci_dev(gdev);
        int i, rc;
 
+       /* No BAR4 allocation: No DMA */
+       if (pci_resource_start(pdev, 4) == 0)
+               return 0;
+
        /* TODO: If we get no DMA mask we should fall back to PIO */
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -583,13 +613,17 @@ int ata_pci_init_bmdma(struct ata_host *host)
 }
 
 /**
- *     ata_pci_init_native_host - acquire native ATA resources and init host
+ *     ata_pci_init_sff_host - acquire native PCI ATA resources and init host
  *     @host: target ATA host
  *
  *     Acquire native PCI ATA resources for @host and initialize the
  *     first two ports of @host accordingly.  Ports marked dummy are
  *     skipped and allocation failure makes the port dummy.
  *
+ *     Note that native PCI resources are valid even for legacy hosts
+ *     as we fix up pdev resources array early in boot, so this
+ *     function can be used for both native and legacy SFF hosts.
+ *
  *     LOCKING:
  *     Inherited from calling layer (may sleep).
  *
@@ -597,7 +631,7 @@ int ata_pci_init_bmdma(struct ata_host *host)
  *     0 if at least one port is initialized, -ENODEV if no port is
  *     available.
  */
-int ata_pci_init_native_host(struct ata_host *host)
+int ata_pci_init_sff_host(struct ata_host *host)
 {
        struct device *gdev = host->dev;
        struct pci_dev *pdev = to_pci_dev(gdev);
@@ -652,7 +686,7 @@ int ata_pci_init_native_host(struct ata_host *host)
 }
 
 /**
- *     ata_pci_prepare_native_host - helper to prepare native PCI ATA host
+ *     ata_pci_prepare_sff_host - helper to prepare native PCI ATA host
  *     @pdev: target PCI device
  *     @ppi: array of port_info, must be enough for two ports
  *     @r_host: out argument for the initialized ATA host
@@ -666,9 +700,9 @@ int ata_pci_init_native_host(struct ata_host *host)
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int ata_pci_prepare_native_host(struct pci_dev *pdev,
-                               const struct ata_port_info * const * ppi,
-                               struct ata_host **r_host)
+int ata_pci_prepare_sff_host(struct pci_dev *pdev,
+                            const struct ata_port_info * const * ppi,
+                            struct ata_host **r_host)
 {
        struct ata_host *host;
        int rc;
@@ -684,7 +718,7 @@ int ata_pci_prepare_native_host(struct pci_dev *pdev,
                goto err_out;
        }
 
-       rc = ata_pci_init_native_host(host);
+       rc = ata_pci_init_sff_host(host);
        if (rc)
                goto err_out;
 
@@ -709,221 +743,6 @@ int ata_pci_prepare_native_host(struct pci_dev *pdev,
        return rc;
 }
 
-struct ata_legacy_devres {
-       unsigned int    mask;
-       unsigned long   cmd_port[2];
-       void __iomem *  cmd_addr[2];
-       void __iomem *  ctl_addr[2];
-       unsigned int    irq[2];
-       void *          irq_dev_id[2];
-};
-
-static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
-{
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               if (!legacy_dr->irq[i])
-                       continue;
-
-               free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
-               legacy_dr->irq[i] = 0;
-               legacy_dr->irq_dev_id[i] = NULL;
-       }
-}
-
-static void ata_legacy_release(struct device *gdev, void *res)
-{
-       struct ata_legacy_devres *this = res;
-       int i;
-
-       ata_legacy_free_irqs(this);
-
-       for (i = 0; i < 2; i++) {
-               if (this->cmd_addr[i])
-                       ioport_unmap(this->cmd_addr[i]);
-               if (this->ctl_addr[i])
-                       ioport_unmap(this->ctl_addr[i]);
-               if (this->cmd_port[i])
-                       release_region(this->cmd_port[i], 8);
-       }
-}
-
-static int ata_init_legacy_port(struct ata_port *ap,
-                               struct ata_legacy_devres *legacy_dr)
-{
-       struct ata_host *host = ap->host;
-       int port_no = ap->port_no;
-       unsigned long cmd_port, ctl_port;
-
-       if (port_no == 0) {
-               cmd_port = ATA_PRIMARY_CMD;
-               ctl_port = ATA_PRIMARY_CTL;
-       } else {
-               cmd_port = ATA_SECONDARY_CMD;
-               ctl_port = ATA_SECONDARY_CTL;
-       }
-
-       /* request cmd_port */
-       if (request_region(cmd_port, 8, "libata"))
-               legacy_dr->cmd_port[port_no] = cmd_port;
-       else {
-               dev_printk(KERN_WARNING, host->dev,
-                          "0x%0lX IDE port busy\n", cmd_port);
-               return -EBUSY;
-       }
-
-       /* iomap cmd and ctl ports */
-       legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
-       legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
-       if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no]) {
-               dev_printk(KERN_WARNING, host->dev,
-                          "failed to map cmd/ctl ports\n");
-               return -ENOMEM;
-       }
-
-       /* init IO addresses */
-       ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
-       ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
-       ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
-       ata_std_ports(&ap->ioaddr);
-
-       return 0;
-}
-
-/**
- *     ata_init_legacy_host - acquire legacy ATA resources and init ATA host
- *     @host: target ATA host
- *     @was_busy: out parameter, indicates whether any port was busy
- *
- *     Acquire legacy ATA resources for the first two ports of @host
- *     and initialize it accordingly.  Ports marked dummy are skipped
- *     and resource acquistion failure makes the port dummy.
- *
- *     LOCKING:
- *     Inherited from calling layer (may sleep).
- *
- *     RETURNS:
- *     0 if at least one port is initialized, -ENODEV if no port is
- *     available.
- */
-static int ata_init_legacy_host(struct ata_host *host, int *was_busy)
-{
-       struct device *gdev = host->dev;
-       struct ata_legacy_devres *legacy_dr;
-       int i, rc;
-
-       if (!devres_open_group(gdev, NULL, GFP_KERNEL))
-               return -ENOMEM;
-
-       rc = -ENOMEM;
-       legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
-                                GFP_KERNEL);
-       if (!legacy_dr)
-               goto err_out;
-       devres_add(gdev, legacy_dr);
-
-       for (i = 0; i < 2; i++) {
-               if (ata_port_is_dummy(host->ports[i]))
-                       continue;
-
-               rc = ata_init_legacy_port(host->ports[i], legacy_dr);
-               if (rc == 0)
-                       legacy_dr->mask |= 1 << i;
-               else {
-                       if (rc == -EBUSY)
-                               (*was_busy)++;
-                       host->ports[i]->ops = &ata_dummy_port_ops;
-               }
-       }
-
-       if (!legacy_dr->mask) {
-               dev_printk(KERN_ERR, gdev, "no available legacy port\n");
-               return -ENODEV;
-       }
-
-       devres_remove_group(gdev, NULL);
-       return 0;
-
- err_out:
-       devres_release_group(gdev, NULL);
-       return rc;
-}
-
-/**
- *     ata_request_legacy_irqs - request legacy ATA IRQs
- *     @host: target ATA host
- *     @handler: array of IRQ handlers
- *     @irq_flags: array of IRQ flags
- *     @dev_id: array of IRQ dev_ids
- *
- *     Request legacy IRQs for non-dummy legacy ports in @host.  All
- *     IRQ parameters are passed as array to allow ports to have
- *     separate IRQ handlers.
- *
- *     LOCKING:
- *     Inherited from calling layer (may sleep).
- *
- *     RETURNS:
- *     0 on success, -errno otherwise.
- */
-static int ata_request_legacy_irqs(struct ata_host *host,
-                                  irq_handler_t const *handler,
-                                  const unsigned int *irq_flags,
-                                  void * const *dev_id)
-{
-       struct device *gdev = host->dev;
-       struct ata_legacy_devres *legacy_dr;
-       int i, rc;
-
-       legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
-       BUG_ON(!legacy_dr);
-
-       for (i = 0; i < 2; i++) {
-               unsigned int irq;
-
-               /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
-               if (i == 0)
-                       irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
-               else
-                       irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
-
-               if (!(legacy_dr->mask & (1 << i)))
-                       continue;
-
-               if (!handler[i]) {
-                       dev_printk(KERN_ERR, gdev,
-                                  "NULL handler specified for port %d\n", i);
-                       rc = -EINVAL;
-                       goto err_out;
-               }
-
-               rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
-                                dev_id[i]);
-               if (rc) {
-                       dev_printk(KERN_ERR, gdev,
-                               "irq %u request failed (errno=%d)\n", irq, rc);
-                       goto err_out;
-               }
-
-               /* record irq allocation in legacy_dr */
-               legacy_dr->irq[i] = irq;
-               legacy_dr->irq_dev_id[i] = dev_id[i];
-
-               /* only used to print info */
-               if (i == 0)
-                       host->irq = irq;
-               else
-                       host->irq2 = irq;
-       }
-
-       return 0;
-
- err_out:
-       ata_legacy_free_irqs(legacy_dr);
-       return rc;
-}
-
 /**
  *     ata_pci_init_one - Initialize/register PCI IDE host controller
  *     @pdev: Controller to be initialized
@@ -1008,35 +827,11 @@ int ata_pci_init_one(struct pci_dev *pdev,
 #endif
        }
 
-       /* alloc and init host */
-       host = ata_host_alloc_pinfo(dev, ppi, 2);
-       if (!host) {
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "failed to allocate ATA host\n");
-               rc = -ENOMEM;
+       /* prepare host */
+       rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+       if (rc)
                goto err_out;
-       }
 
-       if (!legacy_mode) {
-               rc = ata_pci_init_native_host(host);
-               if (rc)
-                       goto err_out;
-       } else {
-               int was_busy = 0;
-
-               rc = ata_init_legacy_host(host, &was_busy);
-               if (was_busy)
-                       pcim_pin_device(pdev);
-               if (rc)
-                       goto err_out;
-
-               /* request respective PCI regions, may fail */
-               rc = pci_request_region(pdev, 1, DRV_NAME);
-               rc = pci_request_region(pdev, 3, DRV_NAME);
-       }
-
-       /* init BMDMA, may fail */
-       ata_pci_init_bmdma(host);
        pci_set_master(pdev);
 
        /* start host and request IRQ */
@@ -1044,19 +839,31 @@ int ata_pci_init_one(struct pci_dev *pdev,
        if (rc)
                goto err_out;
 
-       if (!legacy_mode)
+       if (!legacy_mode) {
                rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
                                      IRQF_SHARED, DRV_NAME, host);
-       else {
-               irq_handler_t handler[2] = { host->ops->irq_handler,
-                                            host->ops->irq_handler };
-               unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
-               void *dev_id[2] = { host, host };
+               if (rc)
+                       goto err_out;
+               host->irq = pdev->irq;
+       } else {
+               if (!ata_port_is_dummy(host->ports[0])) {
+                       host->irq = ATA_PRIMARY_IRQ(pdev);
+                       rc = devm_request_irq(dev, host->irq,
+                                             pi->port_ops->irq_handler,
+                                             IRQF_SHARED, DRV_NAME, host);
+                       if (rc)
+                               goto err_out;
+               }
 
-               rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
+               if (!ata_port_is_dummy(host->ports[1])) {
+                       host->irq2 = ATA_SECONDARY_IRQ(pdev);
+                       rc = devm_request_irq(dev, host->irq2,
+                                             pi->port_ops->irq_handler,
+                                             IRQF_SHARED, DRV_NAME, host);
+                       if (rc)
+                               goto err_out;
+               }
        }
-       if (rc)
-               goto err_out;
 
        /* register */
        rc = ata_host_register(host, pi->sht);