WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [linux-2.6.18-xen] Merge with IA64 tree

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] Merge with IA64 tree
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 10 Oct 2008 10:10:14 -0700
Delivery-date: Fri, 10 Oct 2008 10:10:28 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1223630260 -3600
# Node ID 9c0f24bdbe3ac5febe582c0bd068d517709fc7ed
# Parent  9010d63470ffd5136da7e2a9750f18cef705788e
# Parent  a4b25d49459d85e8c94c286ab8e10b0b9c62a30d
Merge with IA64 tree
---
 drivers/scsi/ahci.c |  690 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 450 insertions(+), 240 deletions(-)

diff -r 9010d63470ff -r 9c0f24bdbe3a drivers/scsi/ahci.c
--- a/drivers/scsi/ahci.c       Fri Oct 10 12:07:01 2008 +0900
+++ b/drivers/scsi/ahci.c       Fri Oct 10 10:17:40 2008 +0100
@@ -93,7 +93,9 @@ enum {
        HOST_AHCI_EN            = (1 << 31), /* AHCI enabled */
 
        /* HOST_CAP bits */
+       HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
+       HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
        HOST_CAP_NCQ            = (1 << 30), /* Native Command Queueing */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -156,6 +158,7 @@ enum {
        PORT_CMD_SPIN_UP        = (1 << 1), /* Spin up device */
        PORT_CMD_START          = (1 << 0), /* Enable port DMA engine */
 
+       PORT_CMD_ICC_MASK       = (0xf << 28), /* i/f ICC state mask */
        PORT_CMD_ICC_ACTIVE     = (0x1 << 28), /* Put i/f in active state */
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
@@ -213,6 +216,10 @@ static void ahci_thaw(struct ata_port *a
 static void ahci_thaw(struct ata_port *ap);
 static void ahci_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);
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int ahci_pci_device_resume(struct pci_dev *pdev);
 static void ahci_remove_one (struct pci_dev *pdev);
 
 static struct scsi_host_template ahci_sht = {
@@ -232,6 +239,8 @@ static struct scsi_host_template ahci_sh
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
+       .suspend                = ata_scsi_device_suspend,
+       .resume                 = ata_scsi_device_resume,
 };
 
 static const struct ata_port_operations ahci_ops = {
@@ -257,6 +266,9 @@ static const struct ata_port_operations 
 
        .error_handler          = ahci_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,
@@ -411,6 +423,8 @@ static struct pci_driver ahci_pci_driver
        .name                   = DRV_NAME,
        .id_table               = ahci_pci_tbl,
        .probe                  = ahci_init_one,
+       .suspend                = ahci_pci_device_suspend,
+       .resume                 = ahci_pci_device_resume,
        .remove                 = ahci_remove_one,
 };
 
@@ -423,108 +437,6 @@ static inline void __iomem *ahci_port_ba
 static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int 
port)
 {
        return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
-}
-
-static int ahci_port_start(struct ata_port *ap)
-{
-       struct device *dev = ap->host_set->dev;
-       struct ahci_host_priv *hpriv = ap->host_set->private_data;
-       struct ahci_port_priv *pp;
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-       void *mem;
-       dma_addr_t mem_dma;
-       int rc;
-
-       pp = kmalloc(sizeof(*pp), GFP_KERNEL);
-       if (!pp)
-               return -ENOMEM;
-       memset(pp, 0, sizeof(*pp));
-
-       rc = ata_pad_alloc(ap, dev);
-       if (rc) {
-               kfree(pp);
-               return rc;
-       }
-
-       mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 
GFP_KERNEL);
-       if (!mem) {
-               ata_pad_free(ap, dev);
-               kfree(pp);
-               return -ENOMEM;
-       }
-       memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
-
-       /*
-        * First item in chunk of DMA memory: 32-slot command table,
-        * 32 bytes each in size
-        */
-       pp->cmd_slot = mem;
-       pp->cmd_slot_dma = mem_dma;
-
-       mem += AHCI_CMD_SLOT_SZ;
-       mem_dma += AHCI_CMD_SLOT_SZ;
-
-       /*
-        * Second item: Received-FIS area
-        */
-       pp->rx_fis = mem;
-       pp->rx_fis_dma = mem_dma;
-
-       mem += AHCI_RX_FIS_SZ;
-       mem_dma += AHCI_RX_FIS_SZ;
-
-       /*
-        * Third item: data area for storing a single command
-        * and its scatter-gather table
-        */
-       pp->cmd_tbl = mem;
-       pp->cmd_tbl_dma = mem_dma;
-
-       ap->private_data = pp;
-
-       if (hpriv->cap & HOST_CAP_64)
-               writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + 
PORT_LST_ADDR_HI);
-       writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
-       readl(port_mmio + PORT_LST_ADDR); /* flush */
-
-       if (hpriv->cap & HOST_CAP_64)
-               writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + 
PORT_FIS_ADDR_HI);
-       writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
-       readl(port_mmio + PORT_FIS_ADDR); /* flush */
-
-       writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
-              PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
-              PORT_CMD_START, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
-
-       return 0;
-}
-
-
-static void ahci_port_stop(struct ata_port *ap)
-{
-       struct device *dev = ap->host_set->dev;
-       struct ahci_port_priv *pp = ap->private_data;
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-       u32 tmp;
-
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
-       writel(tmp, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
-
-       /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
-        * this is slightly incorrect.
-        */
-       msleep(500);
-
-       ap->private_data = NULL;
-       dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
-                         pp->cmd_slot, pp->cmd_slot_dma);
-       ata_pad_free(ap, dev);
-       kfree(pp);
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -561,41 +473,255 @@ static void ahci_scr_write (struct ata_p
        writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static int ahci_stop_engine(struct ata_port *ap)
-{
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-       int work;
+static void ahci_start_engine(void __iomem *port_mmio)
+{
        u32 tmp;
 
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-
-       /* wait for engine to stop.  TODO: this could be
-        * as long as 500 msec
-        */
-       work = 1000;
-       while (work-- > 0) {
-               tmp = readl(port_mmio + PORT_CMD);
-               if ((tmp & PORT_CMD_LIST_ON) == 0)
-                       return 0;
-               udelay(10);
-       }
-
-       return -EIO;
-}
-
-static void ahci_start_engine(struct ata_port *ap)
-{
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-       u32 tmp;
-
+       /* start DMA */
        tmp = readl(port_mmio + PORT_CMD);
        tmp |= PORT_CMD_START;
        writel(tmp, port_mmio + PORT_CMD);
        readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static int ahci_stop_engine(void __iomem *port_mmio)
+{
+       u32 tmp;
+
+       tmp = readl(port_mmio + PORT_CMD);
+
+       /* check if the HBA is idle */
+       if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+               return 0;
+
+       /* setting HBA to idle */
+       tmp &= ~PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+
+       /* wait for engine to stop. This could be as long as 500 msec */
+       tmp = ata_wait_register(port_mmio + PORT_CMD,
+                               PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+       if (tmp & PORT_CMD_LIST_ON)
+               return -EIO;
+
+       return 0;
+}
+
+static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
+                             dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+{
+       u32 tmp;
+
+       /* set FIS registers */
+       if (cap & HOST_CAP_64)
+               writel((cmd_slot_dma >> 16) >> 16, port_mmio + 
PORT_LST_ADDR_HI);
+       writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+
+       if (cap & HOST_CAP_64)
+               writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
+       writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+
+       /* enable FIS reception */
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp |= PORT_CMD_FIS_RX;
+       writel(tmp, port_mmio + PORT_CMD);
+
+       /* flush */
+       readl(port_mmio + PORT_CMD);
+}
+
+static int ahci_stop_fis_rx(void __iomem *port_mmio)
+{
+       u32 tmp;
+
+       /* disable FIS reception */
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp &= ~PORT_CMD_FIS_RX;
+       writel(tmp, port_mmio + PORT_CMD);
+
+       /* wait for completion, spec says 500ms, give it 1000 */
+       tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+                               PORT_CMD_FIS_ON, 10, 1000);
+       if (tmp & PORT_CMD_FIS_ON)
+               return -EBUSY;
+
+       return 0;
+}
+
+static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+{
+       u32 cmd;
+
+       cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+       /* spin up device */
+       if (cap & HOST_CAP_SSS) {
+               cmd |= PORT_CMD_SPIN_UP;
+               writel(cmd, port_mmio + PORT_CMD);
+       }
+
+       /* wake up link */
+       writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
+}
+
+static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+{
+       u32 cmd, scontrol;
+
+       cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+       if (cap & HOST_CAP_SSC) {
+               /* enable transitions to slumber mode */
+               scontrol = readl(port_mmio + PORT_SCR_CTL);
+               if ((scontrol & 0x0f00) > 0x100) {
+                       scontrol &= ~0xf00;
+                       writel(scontrol, port_mmio + PORT_SCR_CTL);
+               }
+
+               /* put device into slumber mode */
+               writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
+
+               /* wait for the transition to complete */
+               ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
+                                 PORT_CMD_ICC_SLUMBER, 1, 50);
+       }
+
+       /* put device into listen mode */
+       if (cap & HOST_CAP_SSS) {
+               /* first set PxSCTL.DET to 0 */
+               scontrol = readl(port_mmio + PORT_SCR_CTL);
+               scontrol &= ~0xf;
+               writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+               /* then set PxCMD.SUD to 0 */
+               cmd &= ~PORT_CMD_SPIN_UP;
+               writel(cmd, port_mmio + PORT_CMD);
+       }
+}
+
+static void ahci_init_port(void __iomem *port_mmio, u32 cap,
+                          dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+{
+       /* power up */
+       ahci_power_up(port_mmio, cap);
+
+       /* enable FIS reception */
+       ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+
+       /* enable DMA */
+       ahci_start_engine(port_mmio);
+}
+
+static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char 
**emsg)
+{
+       int rc;
+
+       /* disable DMA */
+       rc = ahci_stop_engine(port_mmio);
+       if (rc) {
+               *emsg = "failed to stop engine";
+               return rc;
+       }
+
+       /* disable FIS reception */
+       rc = ahci_stop_fis_rx(port_mmio);
+       if (rc) {
+               *emsg = "failed stop FIS RX";
+               return rc;
+       }
+
+       /* put device into slumber mode */
+       ahci_power_down(port_mmio, cap);
+
+       return 0;
+}
+
+static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+{
+       u32 cap_save, tmp;
+
+       cap_save = readl(mmio + HOST_CAP);
+       cap_save &= ( (1<<28) | (1<<17) );
+       cap_save |= (1 << 27);
+
+       /* 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 */
+       }
+
+       /* reset must complete within 1 second, or
+        * the hardware should be considered fried.
+        */
+       ssleep(1);
+
+       tmp = readl(mmio + HOST_CTL);
+       if (tmp & HOST_RESET) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "controller reset failed (0x%x)\n", tmp);
+               return -EIO;
+       }
+
+       writel(HOST_AHCI_EN, mmio + HOST_CTL);
+       (void) readl(mmio + HOST_CTL);  /* flush */
+       writel(cap_save, mmio + HOST_CAP);
+       writel(0xf, mmio + HOST_PORTS_IMPL);
+       (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
+
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+               u16 tmp16;
+
+               /* configure PCS */
+               pci_read_config_word(pdev, 0x92, &tmp16);
+               tmp16 |= 0xf;
+               pci_write_config_word(pdev, 0x92, tmp16);
+       }
+
+       return 0;
+}
+
+static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
+                                int n_ports, u32 cap)
+{
+       int i, rc;
+       u32 tmp;
+
+       for (i = 0; i < n_ports; i++) {
+               void __iomem *port_mmio = ahci_port_base(mmio, i);
+               const char *emsg = NULL;
+
+#if 0 /* BIOSen initialize this incorrectly */
+               if (!(hpriv->port_map & (1 << i)))
+                       continue;
+#endif
+
+               /* make sure port is not active */
+               rc = ahci_deinit_port(port_mmio, cap, &emsg);
+               if (rc)
+                       dev_printk(KERN_WARNING, &pdev->dev,
+                                  "%s (%d)\n", emsg, rc);
+
+               /* clear SError */
+               tmp = readl(port_mmio + PORT_SCR_ERR);
+               VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+               writel(tmp, port_mmio + PORT_SCR_ERR);
+
+               /* clear & turn off port IRQ */
+               tmp = readl(port_mmio + PORT_IRQ_STAT);
+               VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+               if (tmp)
+                       writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+               writel(1 << i, mmio + HOST_IRQ_STAT);
+               writel(0, port_mmio + PORT_IRQ_MASK);
+       }
+
+       tmp = readl(mmio + HOST_CTL);
+       VPRINTK("HOST_CTL 0x%x\n", tmp);
+       writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+       tmp = readl(mmio + HOST_CTL);
+       VPRINTK("HOST_CTL 0x%x\n", tmp);
 }
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
@@ -679,7 +805,7 @@ static int ahci_softreset(struct ata_por
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(ap);
+       rc = ahci_stop_engine(port_mmio);
        if (rc) {
                reason = "failed to stop engine";
                goto fail_restart;
@@ -700,7 +826,7 @@ static int ahci_softreset(struct ata_por
        }
 
        /* restart engine */
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
 
        ata_tf_init(ap->device, &tf);
        fis = pp->cmd_tbl;
@@ -759,7 +885,7 @@ static int ahci_softreset(struct ata_por
        return 0;
 
  fail_restart:
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
@@ -770,11 +896,13 @@ static int ahci_hardreset(struct ata_por
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(ap);
+       ahci_stop_engine(port_mmio);
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
@@ -783,7 +911,7 @@ static int ahci_hardreset(struct ata_por
 
        rc = sata_std_hardreset(ap, class);
 
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
 
        if (rc == 0 && ata_port_online(ap))
                *class = ahci_dev_classify(ap);
@@ -993,8 +1121,14 @@ static void ahci_host_intr(struct ata_po
                return;
 
        /* ignore interim PIO setup fis interrupts */
-       if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) 
-               return;
+       if (ata_tag_valid(ap->active_tag)) {
+               struct ata_queued_cmd *qc =
+                       ata_qc_from_tag(ap, ap->active_tag);
+
+               if (qc && qc->tf.protocol == ATA_PROT_PIO &&
+                   (status & PORT_IRQ_PIOS_FIS))
+                       return;
+       }
 
        if (ata_ratelimit())
                ata_port_printk(ap, KERN_INFO, "spurious interrupt "
@@ -1099,10 +1233,13 @@ static void ahci_thaw(struct ata_port *a
 
 static void ahci_error_handler(struct ata_port *ap)
 {
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
+               ahci_stop_engine(port_mmio);
+               ahci_start_engine(port_mmio);
        }
 
        /* perform recovery */
@@ -1113,15 +1250,176 @@ static void ahci_post_internal_cmd(struc
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 
        if (qc->flags & ATA_QCFLAG_FAILED)
                qc->err_mask |= AC_ERR_OTHER;
 
        if (qc->err_mask) {
                /* make DMA engine forget about the failed command */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
-       }
+               ahci_stop_engine(port_mmio);
+               ahci_start_engine(port_mmio);
+       }
+}
+
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       const char *emsg = NULL;
+       int rc;
+
+       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       if (rc) {
+               ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
+               ahci_init_port(port_mmio, hpriv->cap,
+                              pp->cmd_slot_dma, pp->rx_fis_dma);
+       }
+
+       return rc;
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+       struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+       return 0;
+}
+
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+       void __iomem *mmio = host_set->mmio_base;
+       u32 ctl;
+
+       if (mesg.event == PM_EVENT_SUSPEND) {
+               /* AHCI spec rev1.1 section 8.3.3:
+                * Software must disable interrupts prior to requesting a
+                * transition of the HBA to D3 state.
+                */
+               ctl = readl(mmio + HOST_CTL);
+               ctl &= ~HOST_IRQ_EN;
+               writel(ctl, mmio + HOST_CTL);
+               readl(mmio + HOST_CTL); /* flush */
+       }
+
+       return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int ahci_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+       struct ahci_host_priv *hpriv = host_set->private_data;
+       void __iomem *mmio = host_set->mmio_base;
+       int rc;
+
+       ata_pci_device_do_resume(pdev);
+
+       if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+               rc = ahci_reset_controller(mmio, pdev);
+               if (rc)
+                       return rc;
+
+               ahci_init_controller(mmio, pdev, host_set->n_ports, hpriv->cap);
+       }
+
+       ata_host_set_resume(host_set);
+
+       return 0;
+}
+
+static int ahci_port_start(struct ata_port *ap)
+{
+       struct device *dev = ap->host_set->dev;
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       struct ahci_port_priv *pp;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void *mem;
+       dma_addr_t mem_dma;
+       int rc;
+
+       pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+       if (!pp)
+               return -ENOMEM;
+       memset(pp, 0, sizeof(*pp));
+
+       rc = ata_pad_alloc(ap, dev);
+       if (rc) {
+               kfree(pp);
+               return rc;
+       }
+
+       mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 
GFP_KERNEL);
+       if (!mem) {
+               ata_pad_free(ap, dev);
+               kfree(pp);
+               return -ENOMEM;
+       }
+       memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+
+       /*
+        * First item in chunk of DMA memory: 32-slot command table,
+        * 32 bytes each in size
+        */
+       pp->cmd_slot = mem;
+       pp->cmd_slot_dma = mem_dma;
+
+       mem += AHCI_CMD_SLOT_SZ;
+       mem_dma += AHCI_CMD_SLOT_SZ;
+
+       /*
+        * Second item: Received-FIS area
+        */
+       pp->rx_fis = mem;
+       pp->rx_fis_dma = mem_dma;
+
+       mem += AHCI_RX_FIS_SZ;
+       mem_dma += AHCI_RX_FIS_SZ;
+
+       /*
+        * Third item: data area for storing a single command
+        * and its scatter-gather table
+        */
+       pp->cmd_tbl = mem;
+       pp->cmd_tbl_dma = mem_dma;
+
+       ap->private_data = pp;
+
+       /* initialize port */
+       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+       return 0;
+}
+
+static void ahci_port_stop(struct ata_port *ap)
+{
+       struct device *dev = ap->host_set->dev;
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       const char *emsg = NULL;
+       int rc;
+
+       /* de-initialize port */
+       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       if (rc)
+               ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
+
+       ap->private_data = NULL;
+       dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+                         pp->cmd_slot, pp->cmd_slot_dma);
+       ata_pad_free(ap, dev);
+       kfree(pp);
 }
 
 static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
@@ -1142,47 +1440,12 @@ static int ahci_host_init(struct ata_pro
        struct ahci_host_priv *hpriv = probe_ent->private_data;
        struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        void __iomem *mmio = probe_ent->mmio_base;
-       u32 tmp, cap_save;
-       unsigned int i, j, using_dac;
+       unsigned int i, using_dac;
        int rc;
-       void __iomem *port_mmio;
-
-       cap_save = readl(mmio + HOST_CAP);
-       cap_save &= ( (1<<28) | (1<<17) );
-       cap_save |= (1 << 27);
-
-       /* 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 */
-       }
-
-       /* reset must complete within 1 second, or
-        * the hardware should be considered fried.
-        */
-       ssleep(1);
-
-       tmp = readl(mmio + HOST_CTL);
-       if (tmp & HOST_RESET) {
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "controller reset failed (0x%x)\n", tmp);
-               return -EIO;
-       }
-
-       writel(HOST_AHCI_EN, mmio + HOST_CTL);
-       (void) readl(mmio + HOST_CTL);  /* flush */
-       writel(cap_save, mmio + HOST_CAP);
-       writel(0xf, mmio + HOST_PORTS_IMPL);
-       (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
-
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
-               u16 tmp16;
-
-               pci_read_config_word(pdev, 0x92, &tmp16);
-               tmp16 |= 0xf;
-               pci_write_config_word(pdev, 0x92, tmp16);
-       }
+
+       rc = ahci_reset_controller(mmio, pdev);
+       if (rc)
+               return rc;
 
        hpriv->cap = readl(mmio + HOST_CAP);
        hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
@@ -1218,63 +1481,10 @@ static int ahci_host_init(struct ata_pro
                }
        }
 
-       for (i = 0; i < probe_ent->n_ports; i++) {
-#if 0 /* BIOSen initialize this incorrectly */
-               if (!(hpriv->port_map & (1 << i)))
-                       continue;
-#endif
-
-               port_mmio = ahci_port_base(mmio, i);
-               VPRINTK("mmio %p  port_mmio %p\n", mmio, port_mmio);
-
-               ahci_setup_port(&probe_ent->port[i],
-                               (unsigned long) mmio, i);
-
-               /* make sure port is not active */
-               tmp = readl(port_mmio + PORT_CMD);
-               VPRINTK("PORT_CMD 0x%x\n", tmp);
-               if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
-                          PORT_CMD_FIS_RX | PORT_CMD_START)) {
-                       tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
-                                PORT_CMD_FIS_RX | PORT_CMD_START);
-                       writel(tmp, port_mmio + PORT_CMD);
-                       readl(port_mmio + PORT_CMD); /* flush */
-
-                       /* spec says 500 msecs for each bit, so
-                        * this is slightly incorrect.
-                        */
-                       msleep(500);
-               }
-
-               writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
-
-               j = 0;
-               while (j < 100) {
-                       msleep(10);
-                       tmp = readl(port_mmio + PORT_SCR_STAT);
-                       if ((tmp & 0xf) == 0x3)
-                               break;
-                       j++;
-               }
-
-               tmp = readl(port_mmio + PORT_SCR_ERR);
-               VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
-               writel(tmp, port_mmio + PORT_SCR_ERR);
-
-               /* ack any pending irq events for this port */
-               tmp = readl(port_mmio + PORT_IRQ_STAT);
-               VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
-               if (tmp)
-                       writel(tmp, port_mmio + PORT_IRQ_STAT);
-
-               writel(1 << i, mmio + HOST_IRQ_STAT);
-       }
-
-       tmp = readl(mmio + HOST_CTL);
-       VPRINTK("HOST_CTL 0x%x\n", tmp);
-       writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
-       tmp = readl(mmio + HOST_CTL);
-       VPRINTK("HOST_CTL 0x%x\n", tmp);
+       for (i = 0; i < probe_ent->n_ports; i++)
+               ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
+
+       ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
 
        pci_set_master(pdev);
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] Merge with IA64 tree, Xen patchbot-linux-2.6.18-xen <=