diff options
author | Robert Hancock <hancockr@shaw.ca> | 2007-01-23 20:09:02 -0600 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-01-24 02:01:49 -0500 |
commit | f740d1689d91415cfc749d17138a11ed03b7d38b (patch) | |
tree | 6c329d53cbb44e3d483cce99068a93b30409cbb8 /drivers/ata/sata_nv.c | |
parent | 82490c0937cb455e7e4150455ff52e89a9fc5ab8 (diff) | |
download | kernel_samsung_smdk4412-f740d1689d91415cfc749d17138a11ed03b7d38b.zip kernel_samsung_smdk4412-f740d1689d91415cfc749d17138a11ed03b7d38b.tar.gz kernel_samsung_smdk4412-f740d1689d91415cfc749d17138a11ed03b7d38b.tar.bz2 |
sata_nv: don't rely on NV_INT_DEV indication with ADMA
Several people reported issues with certain drive commands timing out on
sata_nv controllers running in ADMA mode. The commands in question were
non-DMA-mapped commands, usually FLUSH CACHE or FLUSH CACHE EXT.
From experimentation it appears that the NV_INT_DEV indication isn't
always set when a legitimate command completion interrupt is received on
a legacy-mode command, at least not on these controllers in ADMA mode.
When a command is pending on the port, force the flag on always in the
irq_stat value before calling nv_host_intr so that the drive busy state
is always checked by ata_host_intr.
This also fixes some questionable code in nv_host_intr which called
ata_check_status when a command was pending and ata_host_intr returned
"unhandled". If the device interrupted at just the wrong time this could
cause interrupts to be lost.
Signed-off-by: Robert Hancock <hancockr@shaw.ca>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r-- | drivers/ata/sata_nv.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index f6d498e..f7a963e 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -700,7 +700,6 @@ static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) static int nv_host_intr(struct ata_port *ap, u8 irq_stat) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - int handled; /* freeze if hotplugged */ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { @@ -719,13 +718,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat) } /* handle interrupt */ - handled = ata_host_intr(ap, qc); - if (unlikely(!handled)) { - /* spurious, clear it */ - ata_check_status(ap); - } - - return 1; + return ata_host_intr(ap, qc); } static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) @@ -752,6 +745,11 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); + if(ata_tag_valid(ap->active_tag)) + /** NV_INT_DEV indication seems unreliable at times + at least in ADMA mode. Force it on always when a + command is active, to prevent losing interrupts. */ + irq_stat |= NV_INT_DEV; handled += nv_host_intr(ap, irq_stat); continue; } |