From 028a2596336b19a7e3713cfa9fe04d0d32e95876 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 17 Jul 2007 23:48:48 +0400 Subject: ahci.c: fix CONFIG_PM=n compilation Commit df69c9c5438b4e396a64d42608b2a6c48a3e7475 moved only prototype of out of CONFIG_PM. Move function out as well. Box seems to boot fine. Signed-off-by: Alexey Dobriyan Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 11e4eb9f304e..eaec5e506f5e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1519,6 +1519,14 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) } } +static int ahci_port_resume(struct ata_port *ap) +{ + ahci_power_up(ap); + ahci_start_port(ap); + + return 0; +} + #ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) { @@ -1536,14 +1544,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) return rc; } -static int ahci_port_resume(struct ata_port *ap) -{ - ahci_power_up(ap); - ahci_start_port(ap); - - return 0; -} - static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct ata_host *host = dev_get_drvdata(&pdev->dev); -- cgit v1.2.3 From 9977126c4b65c1396b665f7a0eeb8c7dede336f9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:38 +0900 Subject: libata: add @is_cmd to ata_tf_to_fis() Add @is_cmd to ata_tf_to_fis(). This controls bit 7 of the second byte which tells the device whether this H2D FIS is for a command or not. This cleans up ahci a bit and will be used by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index eaec5e506f5e..61c5b6e68de4 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1020,8 +1020,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); tf.ctl |= ATA_SRST; - ata_tf_to_fis(&tf, fis, 0); - fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ + ata_tf_to_fis(&tf, 0, 0, fis); writel(1, port_mmio + PORT_CMD_ISSUE); @@ -1039,8 +1038,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, ahci_fill_cmd_slot(pp, 0, cmd_fis_len); tf.ctl &= ~ATA_SRST; - ata_tf_to_fis(&tf, fis, 0); - fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ + ata_tf_to_fis(&tf, 0, 0, fis); writel(1, port_mmio + PORT_CMD_ISSUE); readl(port_mmio + PORT_CMD_ISSUE); /* flush */ @@ -1088,7 +1086,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(ap->device, &tf); tf.command = 0x80; - ata_tf_to_fis(&tf, d2h_fis, 0); + ata_tf_to_fis(&tf, 0, 0, d2h_fis); rc = sata_std_hardreset(ap, class, deadline); @@ -1205,7 +1203,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) */ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; - ata_tf_to_fis(&qc->tf, cmd_tbl, 0); + ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl); if (is_atapi) { memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); -- cgit v1.2.3 From 2cbb79ebbd4be07041368da5379a64f89f8ad518 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:38 +0900 Subject: ahci: use deadline instead of fixed timeout for 1st FIS for SRST Use deadline instead of fixed timeout for 1st FIS for SRST to improve robustness of SRST. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 61c5b6e68de4..0451600bdcc6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -976,6 +976,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, void __iomem *port_mmio = ahci_port_base(ap); const u32 cmd_fis_len = 5; /* five dwords */ const char *reason = NULL; + unsigned long now, msecs; struct ata_taskfile tf; u32 tmp; u8 *fis; @@ -1016,6 +1017,11 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, fis = pp->cmd_tbl; /* issue the first D2H Register FIS */ + msecs = 0; + now = jiffies; + if (time_after(now, deadline)) + msecs = jiffies_to_msecs(deadline - now); + ahci_fill_cmd_slot(pp, 0, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); @@ -1024,7 +1030,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, writel(1, port_mmio + PORT_CMD_ISSUE); - tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500); + tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs); if (tmp & 0x1) { rc = -EIO; reason = "1st FIS failed"; -- cgit v1.2.3 From d2e75dfffbe9e86e1d646264792ac9bcd2cc4267 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:39 +0900 Subject: 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 Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 69 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) (limited to 'drivers/ata/ahci.c') 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, pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); } -static int ahci_clo(struct ata_port *ap) +static int ahci_kick_engine(struct ata_port *ap, int force_restart) { void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ahci_host_priv *hpriv = ap->host->private_data; u32 tmp; + int busy, rc; - if (!(hpriv->cap & HOST_CAP_CLO)) - return -EOPNOTSUPP; + /* do we need to kick the port? */ + busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ); + if (!busy && !force_restart) + return 0; + + /* stop engine */ + rc = ahci_stop_engine(ap); + if (rc) + goto out_restart; + + /* need to do CLO? */ + if (!busy) { + rc = 0; + goto out_restart; + } + + if (!(hpriv->cap & HOST_CAP_CLO)) { + rc = -EOPNOTSUPP; + goto out_restart; + } + /* perform CLO */ tmp = readl(port_mmio + PORT_CMD); tmp |= PORT_CMD_CLO; writel(tmp, port_mmio + PORT_CMD); + rc = 0; tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); if (tmp & PORT_CMD_CLO) - return -EIO; + rc = -EIO; - return 0; + /* restart engine */ + out_restart: + ahci_start_engine(ap); + return rc; } 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, } /* prepare for SRST (AHCI-1.1 10.4.1) */ - rc = ahci_stop_engine(ap); - if (rc) { - reason = "failed to stop engine"; - goto fail_restart; - } - - /* check BUSY/DRQ, perform Command List Override if necessary */ - if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) { - rc = ahci_clo(ap); - - if (rc == -EOPNOTSUPP) { - reason = "port busy but CLO unavailable"; - goto fail_restart; - } else if (rc) { - reason = "port busy but CLO failed"; - goto fail_restart; - } - } - - /* restart engine */ - ahci_start_engine(ap); + rc = ahci_kick_engine(ap, 1); + if (rc) + ata_port_printk(ap, KERN_WARNING, + "failed to reset engine (errno=%d)", rc); ata_tf_init(ap->device, &tf); fis = pp->cmd_tbl; @@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("EXIT, class=%u\n", *class); return 0; - fail_restart: - ahci_start_engine(ap); fail: ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); return rc; @@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - if (qc->flags & ATA_QCFLAG_FAILED) { - /* make DMA engine forget about the failed command */ - ahci_stop_engine(ap); - ahci_start_engine(ap); - } + /* make DMA engine forget about the failed command */ + if (qc->flags & ATA_QCFLAG_FAILED) + ahci_kick_engine(ap, 1); } static int ahci_port_resume(struct ata_port *ap) -- cgit v1.2.3 From 91c4a2e09267b0ddc8e59d121e3748cd18675739 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:39 +0900 Subject: ahci: separate out ahci_exec_polled_cmd() Separate out ahci_exec_polled_cmd() from ahci_softreset(). This will be used to implement ahci_pmp_read/write(). ahci_exec_polled_cmd() performs reset_engine before returning if the command fails (times out). This is to improve robustness. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 54 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1be238def0ed..db65f4a16021 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -993,17 +993,42 @@ static int ahci_kick_engine(struct ata_port *ap, int force_restart) return rc; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class, - unsigned long deadline) +static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, + struct ata_taskfile *tf, int is_cmd, u16 flags, + unsigned long timeout_msec) { + const u32 cmd_fis_len = 5; /* five dwords */ struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); - const u32 cmd_fis_len = 5; /* five dwords */ + u8 *fis = pp->cmd_tbl; + u32 tmp; + + /* prep the command */ + ata_tf_to_fis(tf, pmp, is_cmd, fis); + ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); + + /* issue & wait */ + writel(1, port_mmio + PORT_CMD_ISSUE); + + if (timeout_msec) { + tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, + 1, timeout_msec); + if (tmp & 0x1) { + ahci_kick_engine(ap, 1); + return -EBUSY; + } + } else + readl(port_mmio + PORT_CMD_ISSUE); /* flush */ + + return 0; +} + +static int ahci_softreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) +{ const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; - u32 tmp; - u8 *fis; int rc; DPRINTK("ENTER\n"); @@ -1021,7 +1046,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, "failed to reset engine (errno=%d)", rc); ata_tf_init(ap->device, &tf); - fis = pp->cmd_tbl; /* issue the first D2H Register FIS */ msecs = 0; @@ -1029,16 +1053,9 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, if (time_after(now, deadline)) msecs = jiffies_to_msecs(deadline - now); - ahci_fill_cmd_slot(pp, 0, - cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); - tf.ctl |= ATA_SRST; - ata_tf_to_fis(&tf, 0, 0, fis); - - writel(1, port_mmio + PORT_CMD_ISSUE); - - tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs); - if (tmp & 0x1) { + if (ahci_exec_polled_cmd(ap, 0, &tf, 0, + AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { rc = -EIO; reason = "1st FIS failed"; goto fail; @@ -1048,13 +1065,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, msleep(1); /* issue the second D2H Register FIS */ - ahci_fill_cmd_slot(pp, 0, cmd_fis_len); - tf.ctl &= ~ATA_SRST; - ata_tf_to_fis(&tf, 0, 0, fis); - - writel(1, port_mmio + PORT_CMD_ISSUE); - readl(port_mmio + PORT_CMD_ISSUE); /* flush */ + ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0); /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for -- cgit v1.2.3 From a9cf5e858100b2f82ad61028c26a1a3de11c4839 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:39 +0900 Subject: ahci: separate out ahci_do_softreset() Separate out ahci_do_softreset() which takes @pmp as its last argument. This will be used to implement ahci_pmp_softreset(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index db65f4a16021..c5034d450c62 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1023,8 +1023,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class, - unsigned long deadline) +static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, + int pmp, unsigned long deadline) { const char *reason = NULL; unsigned long now, msecs; @@ -1054,7 +1054,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, msecs = jiffies_to_msecs(deadline - now); tf.ctl |= ATA_SRST; - if (ahci_exec_polled_cmd(ap, 0, &tf, 0, + if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { rc = -EIO; reason = "1st FIS failed"; @@ -1066,7 +1066,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, /* issue the second D2H Register FIS */ tf.ctl &= ~ATA_SRST; - ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0); + ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for @@ -1094,6 +1094,12 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, return rc; } +static int ahci_softreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) +{ + return ahci_do_softreset(ap, class, 0, deadline); +} + static int ahci_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { -- cgit v1.2.3 From b64bbc39f2122a2276578e40144af69ef01decd4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:39 +0900 Subject: libata: improve EH report formatting Requiring LLDs to format multiple error description messages properly doesn't work too well. Help LLDs a bit by making ata_ehi_push_desc() insert ", " on each invocation. __ata_ehi_push_desc() is the raw version without the automatic separator. While at it, make ehi_desc interface proper functions instead of macros. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c5034d450c62..210292cd8ad1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1289,12 +1289,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) if (irq_stat & PORT_IRQ_IF_ERR) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, ", interface fatal error"); + ata_ehi_push_desc(ehi, "interface fatal error"); } if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? + ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? "connection status changed" : "PHY RDY changed"); } @@ -1303,7 +1303,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) err_mask |= AC_ERR_HSM; action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", + ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x", unk[0], unk[1], unk[2], unk[3]); } -- cgit v1.2.3 From da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: libata: make ->scr_read/write callbacks return error code Convert ->scr_read/write callbacks to return error code to better indicate failure. This will help handling of SCR_NOTIFICATION. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 210292cd8ad1..e044d6477a0f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -216,8 +216,8 @@ struct ahci_port_priv { unsigned int ncq_saw_sdb:1; }; -static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); static void ahci_irq_clear(struct ata_port *ap); @@ -625,7 +625,7 @@ static void ahci_restore_initial_config(struct ata_host *host) (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ } -static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) +static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { unsigned int sc_reg; @@ -635,15 +635,15 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) case SCR_ERROR: sc_reg = 2; break; case SCR_ACTIVE: sc_reg = 3; break; default: - return 0xffffffffU; + return -EINVAL; } - return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, - u32 val) +static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { unsigned int sc_reg; @@ -653,10 +653,11 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, case SCR_ERROR: sc_reg = 2; break; case SCR_ACTIVE: sc_reg = 3; break; default: - return; + return -EINVAL; } writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } static void ahci_start_engine(struct ata_port *ap) @@ -1133,6 +1134,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { + u32 serror; int rc; DPRINTK("ENTER\n"); @@ -1143,7 +1145,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, deadline); /* vt8251 needs SError cleared for the port to operate */ - ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); + ahci_scr_read(ap, SCR_ERROR, &serror); + ahci_scr_write(ap, SCR_ERROR, serror); ahci_start_engine(ap); @@ -1265,7 +1268,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ata_ehi_clear_desc(ehi); /* AHCI needs SError cleared; otherwise, it might lock up */ - serror = ahci_scr_read(ap, SCR_ERROR); + ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_write(ap, SCR_ERROR, serror); /* analyze @irq_stat */ -- cgit v1.2.3 From 274c1fde5c775a53331427d454745b9ecc5c783b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: ahci: make NO_NCQ handling more consistent ahci_save_initial_config() is responsible for reading, screening the host CAP register and storing the modified result into hpriv->cap for the rest of the driver. Move ATA_FLAG_NO_NCQ handling into ahci_save_initial_config(). It's more consistent this way and the rest of the driver can always refer to hpriv->cap to determine configured capability. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e044d6477a0f..9475e5619af1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -545,13 +545,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev, hpriv->saved_cap = cap = readl(mmio + HOST_CAP); hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); - /* some chips lie about 64bit support */ + /* some chips have errata preventing 64bit use */ if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do 64bit DMA, forcing 32bit\n"); cap &= ~HOST_CAP_64; } + if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can't do NCQ, turning off CAP_NCQ\n"); + cap &= ~HOST_CAP_NCQ; + } + /* fixup zero port_map */ if (!port_map) { port_map = (1 << ahci_nr_ports(cap)) - 1; @@ -1822,7 +1828,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ahci_save_initial_config(pdev, &pi, hpriv); /* prepare host */ - if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ)) + if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); -- cgit v1.2.3 From 203ef6c456ad70e660cca67921d3d872b13aa516 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: ahci: implement SCR_NOTIFICATION r/w Make ahci_scr_read/write() handle SCR_NOTIFICATION if the controller supports it. Also, print "sntf" in the cap line if supported. While at it, convert eight space into a tab in ahci_print_info(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 68 +++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9475e5619af1..de8bffbf4bd3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -99,6 +99,7 @@ enum { 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_SNTF = (1 << 29), /* SNotification register */ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ @@ -113,11 +114,11 @@ enum { PORT_TFDATA = 0x20, /* taskfile data */ PORT_SIG = 0x24, /* device TF signature */ PORT_CMD_ISSUE = 0x38, /* command issue */ - PORT_SCR = 0x28, /* SATA phy register block */ PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ + PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ /* PORT_IRQ_{STAT,MASK} bits */ PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ @@ -631,39 +632,45 @@ static void ahci_restore_initial_config(struct ata_host *host) (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ } -static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) +static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) { - unsigned int sc_reg; - - switch (sc_reg_in) { - case SCR_STATUS: sc_reg = 0; break; - case SCR_CONTROL: sc_reg = 1; break; - case SCR_ERROR: sc_reg = 2; break; - case SCR_ACTIVE: sc_reg = 3; break; - default: - return -EINVAL; - } + static const int offset[] = { + [SCR_STATUS] = PORT_SCR_STAT, + [SCR_CONTROL] = PORT_SCR_CTL, + [SCR_ERROR] = PORT_SCR_ERR, + [SCR_ACTIVE] = PORT_SCR_ACT, + [SCR_NOTIFICATION] = PORT_SCR_NTF, + }; + struct ahci_host_priv *hpriv = ap->host->private_data; - *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + if (sc_reg < ARRAY_SIZE(offset) && + (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) + return offset[sc_reg]; return 0; } - -static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { - unsigned int sc_reg; - - switch (sc_reg_in) { - case SCR_STATUS: sc_reg = 0; break; - case SCR_CONTROL: sc_reg = 1; break; - case SCR_ERROR: sc_reg = 2; break; - case SCR_ACTIVE: sc_reg = 3; break; - default: - return -EINVAL; + void __iomem *port_mmio = ahci_port_base(ap); + int offset = ahci_scr_offset(ap, sc_reg); + + if (offset) { + *val = readl(port_mmio + offset); + return 0; } + return -EINVAL; +} - writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); - return 0; +static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + void __iomem *port_mmio = ahci_port_base(ap); + int offset = ahci_scr_offset(ap, sc_reg); + + if (offset) { + writel(val, port_mmio + offset); + return 0; + } + return -EINVAL; } static void ahci_start_engine(struct ata_port *ap) @@ -1768,12 +1775,13 @@ static void ahci_print_info(struct ata_host *host) dev_printk(KERN_INFO, &pdev->dev, "flags: " - "%s%s%s%s%s%s" - "%s%s%s%s%s%s%s\n" + "%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%s\n" , cap & (1 << 31) ? "64bit " : "", cap & (1 << 30) ? "ncq " : "", + cap & (1 << 29) ? "sntf " : "", cap & (1 << 28) ? "ilck " : "", cap & (1 << 27) ? "stag " : "", cap & (1 << 26) ? "pm " : "", @@ -1842,10 +1850,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *port_mmio = ahci_port_base(ap); /* standard SATA port setup */ - if (hpriv->port_map & (1 << i)) { + if (hpriv->port_map & (1 << i)) ap->ioaddr.cmd_addr = port_mmio; - ap->ioaddr.scr_addr = port_mmio + PORT_SCR; - } /* disabled/not-implemented port */ else -- cgit v1.2.3 From badc2341579511a247f5993865aa68379e283c5c Mon Sep 17 00:00:00 2001 From: su henry Date: Fri, 20 Jul 2007 08:07:46 -0400 Subject: The SATA controller device ID is different according to the onchip SATA type set in the system BIOS: Device Device ID SATA in IDE mode 0x4390 SATA in AHCI mode 0x4391 SATA in non-raid5 driver 0x4392 SATA in raid5 driver 0x4393 Although the device ID is different, they use the same AHCI driver .The attached file is the patch for adding these device IDs for ATI SB700. Signed-off-by: henry.su.ati@gmail.com Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/ata/ahci.c') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index de8bffbf4bd3..06f212ff2b4f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -418,7 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* ATI */ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ - { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */ + { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */ + { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */ + { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */ + { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */ /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ -- cgit v1.2.3