diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 69 |
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 | ||
951 | static int ahci_clo(struct ata_port *ap) | 951 | static 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 | ||
972 | static int ahci_softreset(struct ata_port *ap, unsigned int *class, | 996 | static 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 | ||
1526 | static int ahci_port_resume(struct ata_port *ap) | 1529 | static int ahci_port_resume(struct ata_port *ap) |