All of lore.kernel.org
 help / color / mirror / Atom feed
From: "zhao, forrest" <forrest.zhao@intel.com>
To: jgarzik@pobox.com, htejun@gmail.com, hare@suse.de, axboe@suse.de
Cc: linux-ide@vger.kernel.org
Subject: [PATCH 6/6] Implement the AHCI suspend/resume
Date: Mon, 10 Jul 2006 15:34:59 +0800	[thread overview]
Message-ID: <1152516899.7132.276.camel@forrest26.sh.intel.com> (raw)

This patch implements the AHCI suspend/resume.


Signed-off-by: Forrest Zhao <forrest.zhaot@intel.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Jens Axboe <axboe@suse.de>


---

 drivers/scsi/ahci.c |  127 ++++++++++++++++++++++++++++++++++++++++++++
+++++++
 1 files changed, 127 insertions(+), 0 deletions(-)

6fd581dceefd2f40212c468a3e0c7c49c60c0500
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index dc76798..28e1419 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -221,9 +221,12 @@ static void ahci_freeze(struct ata_port 
 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_pci_device_suspend(struct pci_dev *pdev, pm_message_t
state);
+static int ahci_pci_device_resume(struct pci_dev *pdev);
 static int ahci_port_standby(void __iomem *port_mmio, u32 cap);
 static int ahci_port_spinup(void __iomem *port_mmio, u32 cap);
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t state);
+static int ahci_port_resume(struct ata_port *ap);
 static void ahci_remove_one (struct pci_dev *pdev);
 
 static struct scsi_host_template ahci_sht = {
@@ -243,6 +246,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,
+	.resume			= ata_scsi_device_resume,
+	.suspend		= ata_scsi_device_suspend,
 };
 
 static const struct ata_port_operations ahci_ops = {
@@ -371,6 +376,8 @@ static struct pci_driver ahci_pci_driver
 	.id_table		= ahci_pci_tbl,
 	.probe			= ahci_init_one,
 	.remove			= ahci_remove_one,
+	.suspend		= ahci_pci_device_suspend,
+	.resume			= ahci_pci_device_resume,
 };
 
 
@@ -507,6 +514,57 @@ static int ahci_port_suspend(struct ata_
 	return rc;
 }
 
+static int ahci_port_resume(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->host_set->mmio_base;
+	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	struct ahci_host_priv *hpriv = ap->host_set->private_data;
+	struct ahci_port_priv *pp = ap->private_data;
+	int rc;
+	u32 tmp;
+
+	/*
+	 * Enable FIS reception
+	 */
+	ahci_start_fis_rx(port_mmio, pp, hpriv);
+
+	rc = ahci_port_spinup(port_mmio, hpriv->cap);
+	if (rc)
+		ata_port_printk(ap, KERN_WARNING, "Could not spinup device"
+				" (%d)\n", rc);
+
+	/*
+	 * Clear error status
+	 */
+	tmp = readl(port_mmio + PORT_SCR_ERR);
+	writel(tmp, port_mmio + PORT_SCR_ERR);
+	/*
+	 * Clear interrupt status
+	 */
+	tmp = readl(mmio + HOST_CTL);
+	if (!(tmp & HOST_IRQ_EN)) {
+		u32 irq_stat;
+
+		/* ack any pending irq events for this port */
+		irq_stat = readl(port_mmio + PORT_IRQ_STAT);
+		if (irq_stat)
+			writel(irq_stat, port_mmio + PORT_IRQ_STAT);
+
+		/* set irq mask (enables interrupts) */
+		writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+	}
+
+	/*
+	 * Enable DMA
+	 */
+	rc = ahci_start_engine(port_mmio);
+	if (rc)
+		ata_port_printk(ap, KERN_WARNING, "Can't start DMA engine"
+				" (%d)\n", rc);
+
+	return rc;
+}
+
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
 {
 	unsigned int sc_reg;
@@ -1022,6 +1080,75 @@ static unsigned int ahci_fill_sg(struct 
 	return n_sg;
 }
 
+int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+	void __iomem *mmio = host_set->mmio_base;
+	u32 tmp;
+	int i;
+
+	/* First suspend all ports */
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+		ahci_port_suspend(ap, state);
+	}
+
+	/*
+	 * AHCI spec rev1.1 section 8.3.3:
+	 * Software must disable interrupts prior to
+	 * requesting a transition of the HBA to
+	 * D3 state.
+	 */
+	tmp = readl(mmio + HOST_CTL);
+	tmp &= ~HOST_IRQ_EN;
+	writel(tmp, mmio + HOST_CTL);
+	tmp = readl(mmio + HOST_CTL); /* flush */
+
+	ata_pci_device_do_suspend(pdev, state);
+
+	return 0;
+}
+
+int ahci_pci_device_resume(struct pci_dev *pdev)
+{
+	struct device *dev = pci_dev_to_dev(pdev);
+	struct ata_host_set *host_set = dev_get_drvdata(dev);
+	void __iomem *mmio = host_set->mmio_base;
+	struct ata_port *ap;
+	u32 i, tmp, irq_stat;
+
+	tmp = readl(mmio + HOST_CTL);
+	if (!(tmp & HOST_AHCI_EN)) {
+		tmp |= HOST_AHCI_EN;
+		writel(tmp, mmio + HOST_CTL);
+		tmp = readl(mmio + HOST_CTL);
+	}
+
+	ata_pci_device_do_resume(pdev);
+
+	/* Resume all ports */
+	for (i = 0; i < host_set->n_ports; i++) {
+		ap = host_set->ports[i];
+		ahci_port_resume(ap);
+	}
+
+	/*
+	 * Clear interrupt status and enable interrupt
+	 */
+	if (!(tmp & HOST_IRQ_EN)) {
+		irq_stat = readl(mmio + HOST_IRQ_STAT);
+		if (irq_stat)
+			writel(irq_stat, mmio + HOST_IRQ_STAT);
+		tmp |= HOST_IRQ_EN;
+		writel(tmp, mmio + HOST_CTL);
+		tmp = readl(mmio + HOST_CTL);
+	}
+
+	return 0;
+}
+
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-- 
1.2.6


             reply	other threads:[~2006-07-10  7:48 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-10  7:34 zhao, forrest [this message]
  -- strict thread matches above, loose matches on Subject: below --
2006-07-13  5:39 [PATCH 6/6] Implement the AHCI suspend/resume zhao, forrest
2006-07-11  6:42 zhao, forrest
2006-07-10  3:35 zhao, forrest
2006-07-10  7:34 ` zhao, forrest
2006-06-29  8:21 zhao, forrest
2006-06-06 10:17 zhao, forrest
2006-06-02  7:46 zhao, forrest
2006-06-02  8:21 ` Hannes Reinecke
2006-06-02  8:34   ` Tejun Heo
2006-06-03 13:35 ` Tejun Heo
2006-06-05  5:05   ` zhao, forrest

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1152516899.7132.276.camel@forrest26.sh.intel.com \
    --to=forrest.zhao@intel.com \
    --cc=axboe@suse.de \
    --cc=hare@suse.de \
    --cc=htejun@gmail.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.