Commit ad616ffb authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

[PATCH] ahci: update ahci-vt8251 reset sequence

ahci-vt8251

* requires hardreset after PHY status change

* doesn't clear BSY on signature FIS after hardreset

* needs SError cleared for the port to operate after hardreset

This patch implements ahci_vt8251_hardreset() and sets
ATA_FLAG_HRST_TO_RESUME to handle the above behaviors.  This fixes EH
including hotplug on vt8251.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent b6103f6d
...@@ -215,6 +215,7 @@ static u8 ahci_check_status(struct ata_port *ap); ...@@ -215,6 +215,7 @@ static u8 ahci_check_status(struct ata_port *ap);
static void ahci_freeze(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_port_resume(struct ata_port *ap); static int ahci_port_resume(struct ata_port *ap);
...@@ -274,6 +275,37 @@ static const struct ata_port_operations ahci_ops = { ...@@ -274,6 +275,37 @@ static const struct ata_port_operations ahci_ops = {
.port_stop = ahci_port_stop, .port_stop = ahci_port_stop,
}; };
static const struct ata_port_operations ahci_vt8251_ops = {
.port_disable = ata_port_disable,
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
.freeze = ahci_freeze,
.thaw = ahci_thaw,
.error_handler = ahci_vt8251_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
static const struct ata_port_info ahci_port_info[] = { static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */ /* board_ahci */
{ {
...@@ -290,10 +322,11 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -290,10 +322,11 @@ static const struct ata_port_info ahci_port_info[] = {
.sht = &ahci_sht, .sht = &ahci_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_NO_NCQ, ATA_FLAG_SKIP_D2H_BSY |
ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
.pio_mask = 0x1f, /* pio0-4 */ .pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops, .port_ops = &ahci_vt8251_ops,
}, },
/* board_ahci_ign_iferr */ /* board_ahci_ign_iferr */
{ {
...@@ -864,6 +897,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) ...@@ -864,6 +897,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
return rc; return rc;
} }
static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
{
void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
DPRINTK("ENTER\n");
ahci_stop_engine(port_mmio);
rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
/* vt8251 needs SError cleared for the port to operate */
ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
ahci_start_engine(port_mmio);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
/* vt8251 doesn't clear BSY on signature FIS reception,
* request follow-up softreset.
*/
return rc ?: -EAGAIN;
}
static void ahci_postreset(struct ata_port *ap, unsigned int *class) static void ahci_postreset(struct ata_port *ap, unsigned int *class)
{ {
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
...@@ -1187,6 +1245,22 @@ static void ahci_error_handler(struct ata_port *ap) ...@@ -1187,6 +1245,22 @@ static void ahci_error_handler(struct ata_port *ap)
ahci_postreset); ahci_postreset);
} }
static void ahci_vt8251_error_handler(struct ata_port *ap)
{
void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(port_mmio);
ahci_start_engine(port_mmio);
}
/* perform recovery */
ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
ahci_postreset);
}
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment