aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-07-16 01:29:39 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-20 08:02:10 -0400
commitd2e75dfffbe9e86e1d646264792ac9bcd2cc4267 (patch)
treebe742ccdbefc5ddb0db031d9fd95717d7641b950 /drivers/ata
parent2cbb79ebbd4be07041368da5379a64f89f8ad518 (diff)
ahci: separate out ahci_kick_engine()
Separate out stop_engine - CLO - start_engine sequence from ahci_softreset() and ahci_clo() into ahci_reset_engine() and use it in ahci_softreset() and ahci_post_internal_cmd(). The function will also be used to prepare for and clean up after PMP register access commands. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c69
1 files changed, 36 insertions, 33 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 0451600bdcc6..1be238def0ed 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -948,25 +948,49 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
948 pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 948 pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
949} 949}
950 950
951static int ahci_clo(struct ata_port *ap) 951static int ahci_kick_engine(struct ata_port *ap, int force_restart)
952{ 952{
953 void __iomem *port_mmio = ap->ioaddr.cmd_addr; 953 void __iomem *port_mmio = ap->ioaddr.cmd_addr;
954 struct ahci_host_priv *hpriv = ap->host->private_data; 954 struct ahci_host_priv *hpriv = ap->host->private_data;
955 u32 tmp; 955 u32 tmp;
956 int busy, rc;
956 957
957 if (!(hpriv->cap & HOST_CAP_CLO)) 958 /* do we need to kick the port? */
958 return -EOPNOTSUPP; 959 busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
960 if (!busy && !force_restart)
961 return 0;
962
963 /* stop engine */
964 rc = ahci_stop_engine(ap);
965 if (rc)
966 goto out_restart;
967
968 /* need to do CLO? */
969 if (!busy) {
970 rc = 0;
971 goto out_restart;
972 }
973
974 if (!(hpriv->cap & HOST_CAP_CLO)) {
975 rc = -EOPNOTSUPP;
976 goto out_restart;
977 }
959 978
979 /* perform CLO */
960 tmp = readl(port_mmio + PORT_CMD); 980 tmp = readl(port_mmio + PORT_CMD);
961 tmp |= PORT_CMD_CLO; 981 tmp |= PORT_CMD_CLO;
962 writel(tmp, port_mmio + PORT_CMD); 982 writel(tmp, port_mmio + PORT_CMD);
963 983
984 rc = 0;
964 tmp = ata_wait_register(port_mmio + PORT_CMD, 985 tmp = ata_wait_register(port_mmio + PORT_CMD,
965 PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 986 PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
966 if (tmp & PORT_CMD_CLO) 987 if (tmp & PORT_CMD_CLO)
967 return -EIO; 988 rc = -EIO;
968 989
969 return 0; 990 /* restart engine */
991 out_restart:
992 ahci_start_engine(ap);
993 return rc;
970} 994}
971 995
972static int ahci_softreset(struct ata_port *ap, unsigned int *class, 996static int ahci_softreset(struct ata_port *ap, unsigned int *class,
@@ -991,27 +1015,10 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
991 } 1015 }
992 1016
993 /* prepare for SRST (AHCI-1.1 10.4.1) */ 1017 /* prepare for SRST (AHCI-1.1 10.4.1) */
994 rc = ahci_stop_engine(ap); 1018 rc = ahci_kick_engine(ap, 1);
995 if (rc) { 1019 if (rc)
996 reason = "failed to stop engine"; 1020 ata_port_printk(ap, KERN_WARNING,
997 goto fail_restart; 1021 "failed to reset engine (errno=%d)", rc);
998 }
999
1000 /* check BUSY/DRQ, perform Command List Override if necessary */
1001 if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
1002 rc = ahci_clo(ap);
1003
1004 if (rc == -EOPNOTSUPP) {
1005 reason = "port busy but CLO unavailable";
1006 goto fail_restart;
1007 } else if (rc) {
1008 reason = "port busy but CLO failed";
1009 goto fail_restart;
1010 }
1011 }
1012
1013 /* restart engine */
1014 ahci_start_engine(ap);
1015 1022
1016 ata_tf_init(ap->device, &tf); 1023 ata_tf_init(ap->device, &tf);
1017 fis = pp->cmd_tbl; 1024 fis = pp->cmd_tbl;
@@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
1070 DPRINTK("EXIT, class=%u\n", *class); 1077 DPRINTK("EXIT, class=%u\n", *class);
1071 return 0; 1078 return 0;
1072 1079
1073 fail_restart:
1074 ahci_start_engine(ap);
1075 fail: 1080 fail:
1076 ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); 1081 ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
1077 return rc; 1082 return rc;
@@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1516{ 1521{
1517 struct ata_port *ap = qc->ap; 1522 struct ata_port *ap = qc->ap;
1518 1523
1519 if (qc->flags & ATA_QCFLAG_FAILED) { 1524 /* make DMA engine forget about the failed command */
1520 /* make DMA engine forget about the failed command */ 1525 if (qc->flags & ATA_QCFLAG_FAILED)
1521 ahci_stop_engine(ap); 1526 ahci_kick_engine(ap, 1);
1522 ahci_start_engine(ap);
1523 }
1524} 1527}
1525 1528
1526static int ahci_port_resume(struct ata_port *ap) 1529static int ahci_port_resume(struct ata_port *ap)