The definition of ahci_port_standby() and ahci_port_spinup()
PATCH 3/6 The 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 ().
Signed-off-by Forrest Zhao <[email protected]>
Signed-off-by Hannes Reinecke <[email protected]>
Signed-off-by Jens Axboe <[email protected]>
---
drivers/scsi/ahci.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ +++++++ 1 files changed, 98 insertions(+), 0 deletions(-)
9ea9213fa3b37b84727d2ab1d911a84f8e205412
drivers/scsi/ahci.c +98 -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 slumber state */
@@ -218,6 +221,8 @@ static void ahci_freeze(struct ata_portstatic 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 __iomreadl (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