Commit e4006077 authored by Mark Lord's avatar Mark Lord Committed by Jeff Garzik

sata_mv: fis irq register fixes

Fix handling of the FIS_IRQ_CAUSE register in sata_mv.

This register exists *only* on GenIIe devices, so don't bother
writing to it on older chips.  Also, it has to be read/cleared
in mv_err_intr() before clearing the main ERR_IRQ_CAUSE register.

This keeps sata_mv from getting stuck forever on certain error types.
Signed-off-by: default avatarMark Lord <mlord@pobox.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 9dcffd99
...@@ -886,7 +886,8 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio, ...@@ -886,7 +886,8 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
mv_edma_cfg(ap, want_ncq); mv_edma_cfg(ap, want_ncq);
/* clear FIS IRQ Cause */ /* clear FIS IRQ Cause */
writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS); if (IS_GEN_IIE(hpriv))
writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
mv_set_edma_ptrs(port_mmio, hpriv, pp); mv_set_edma_ptrs(port_mmio, hpriv, pp);
...@@ -1812,6 +1813,7 @@ static void mv_err_intr(struct ata_port *ap) ...@@ -1812,6 +1813,7 @@ static void mv_err_intr(struct ata_port *ap)
{ {
void __iomem *port_mmio = mv_ap_base(ap); void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0; u32 edma_err_cause, eh_freeze_mask, serr = 0;
u32 fis_cause = 0;
struct mv_port_priv *pp = ap->private_data; struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data; struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int action = 0, err_mask = 0; unsigned int action = 0, err_mask = 0;
...@@ -1821,16 +1823,19 @@ static void mv_err_intr(struct ata_port *ap) ...@@ -1821,16 +1823,19 @@ static void mv_err_intr(struct ata_port *ap)
/* /*
* Read and clear the SError and err_cause bits. * Read and clear the SError and err_cause bits.
* For GenIIe, if EDMA_ERR_TRANS_IRQ_7 is set, we also must read/clear
* the FIS_IRQ_CAUSE register before clearing edma_err_cause.
*/ */
sata_scr_read(&ap->link, SCR_ERROR, &serr); sata_scr_read(&ap->link, SCR_ERROR, &serr);
sata_scr_write_flush(&ap->link, SCR_ERROR, serr); sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
fis_cause = readl(port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
writelfl(~fis_cause, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
}
writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
ata_port_printk(ap, KERN_INFO, "%s: err_cause=%08x pp_flags=0x%x\n",
__func__, edma_err_cause, pp->pp_flags);
if (edma_err_cause & EDMA_ERR_DEV) { if (edma_err_cause & EDMA_ERR_DEV) {
/* /*
* Device errors during FIS-based switching operation * Device errors during FIS-based switching operation
...@@ -1844,6 +1849,9 @@ static void mv_err_intr(struct ata_port *ap) ...@@ -1844,6 +1849,9 @@ static void mv_err_intr(struct ata_port *ap)
ata_ehi_clear_desc(ehi); ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x", ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
edma_err_cause, pp->pp_flags); edma_err_cause, pp->pp_flags);
if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7))
ata_ehi_push_desc(ehi, "fis_cause=%08x", fis_cause);
/* /*
* All generations share these EDMA error cause bits: * All generations share these EDMA error cause bits:
*/ */
......
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