ahci: definition of ahci_port_standby() and ahci_port_spinup()
PATCH 2/5 ahci: definition of ahci_port_standby() and ahci_port_spinup()
Put port power management and staggered-spinup related operations during the power state transition into ahci_port_standby() and ahci_port_spinup ().
---
drivers/scsi/ahci.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ +++++++ 1 files changed, 98 insertions(+), 0 deletions(-)
9ea9213fa3b37b84727d2ab1d911a84f8e205412
drivers/scsi/ahci.c +1 -0
@@ -92,7 +92,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 */
@@ -155,6 +157,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 slumberstate */
@@ -218,6 +221,8 @@ 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_port_standby(void __iomem *port_mmio, u32 cap); +static int ahci_port_spinup(void __iomem *port_mmio, u32 cap);
static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
@@ -645,6 +650,99 @@ static void ahci_start_fis_rx(void __iom
readl(port_mmio + PORT_CMD); /* flush */
}
+static int ahci_port_standby(void __iomem *port_mmio, u32 cap) +{
+ u32 tmp, scontrol, sstatus;
+
+ tmp = readl(port_mmio + PORT_CMD);
+ /*
+ * AHCI Rev1.1 Section 5.3.2.3: + * Software is only allowed to program the PxCMD.FRE, + * PxCMD.POD, PxSCTL.DET, and PxCMD.SUD register bits + * when PxCMD.ST is set to '0' + */
+ if (tmp & PORT_CMD_START)
+ return -EBUSY;
+
+ 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
+ */
+ tmp |= PORT_CMD_ICC_SLUMBER; + writel(tmp, port_mmio + PORT_CMD); + tmp = readl(port_mmio + PORT_CMD); + + /* + * Actually, we should wait for the device to + * enter slumber mode by checking + * sstatus & 0xf00 == 6 + */
+ sstatus = readl(port_mmio + PORT_SCR_STAT);
+ }
+
+ /*
+ * 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
+ */
+ tmp = readl(port_mmio + PORT_CMD); + tmp &= ~PORT_CMD_SPIN_UP; + writel(tmp, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* flush */
+ }
+
+ return 0;
+}
+
+static int ahci_port_spinup(void __iomem *port_mmio, u32 cap) +{
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_CMD);
+ /*
+ * AHCI Rev1.1 Section 5.3.2.3: + * Software is only allowed to program the PxCMD.FRE, + * PxCMD.POD, PxSCTL.DET, and PxCMD.SUD register bits + * when PxCMD.ST is set to '0' + */
+ if (tmp & PORT_CMD_START)
+ return -EBUSY;
+
+ /*
+ * Spin up device
+ */
+ if (cap & HOST_CAP_SSS) {
+ tmp |= PORT_CMD_SPIN_UP;
+ writel(tmp, port_mmio + PORT_CMD);
+ tmp = readl(port_mmio + PORT_CMD);
+ }
+
+ if ((tmp & PORT_CMD_ICC_MASK) != PORT_CMD_ICC_ACTIVE) {
+ tmp |= PORT_CMD_ICC_ACTIVE;
+ writel(tmp, port_mmio + PORT_CMD);
+ tmp = readl(port_mmio + PORT_CMD);+ }
+
+ return 0;
+}
+
static unsigned int ahci_dev_classify(struct ata_port *ap)
{
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;Signature · 1 line
1.2.6