diff options
author | Tejun Heo <htejun@gmail.com> | 2006-11-16 22:24:22 -0500 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-12-03 03:56:24 -0500 |
commit | 0f0a3ad3741fd93461fcfb85dc577103c58d9be8 (patch) | |
tree | 1d91117b58b6c3878f6b346e8e8f4c7b93dbca9f /drivers/ata | |
parent | ea54763f8a7c51b9f8fcb14431812ae63fcbaf96 (diff) |
[PATCH] libata: make sure IRQ is cleared after ata_bmdma_freeze()
Now that BMDMA status is recorded in irq handler. ata_bmdma_freeze()
is free to manipulate host status. Under certain circumstances, some
controllers (ICH7 in enhanced mode w/ IRQ shared) raise IRQ when CTL
register is written to and ATA_NIEN doesn't mask it.
This patch makes ata_bmdma_freeze() clear all pending IRQs after
freezing a port. This change makes explicit clearing in
ata_device_add() unnecessary and thus kills it. The removed code was
SFF-specific and was in the wrong place.
Note that ->freeze() handler is always called under ap->lock held and
irq disabled. Even if CTL manipulation causes stuck IRQ, it's cleared
immediately. This should be safe (enough) even in SMP environment.
More correct solution is to mask the IRQ from IRQ controller but that
would be an overkill.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 5 | ||||
-rw-r--r-- | drivers/ata/libata-sff.c | 8 |
2 files changed, 10 insertions, 3 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f53ea725bce..47c70392ec4d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -5681,9 +5681,8 @@ int ata_device_add(const struct ata_probe_ent *ent) | |||
5681 | ap->ioaddr.bmdma_addr, | 5681 | ap->ioaddr.bmdma_addr, |
5682 | irq_line); | 5682 | irq_line); |
5683 | 5683 | ||
5684 | ata_chk_status(ap); | 5684 | /* freeze port before requesting IRQ */ |
5685 | host->ops->irq_clear(ap); | 5685 | ata_eh_freeze_port(ap); |
5686 | ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */ | ||
5687 | } | 5686 | } |
5688 | 5687 | ||
5689 | /* obtain irq, that may be shared between channels */ | 5688 | /* obtain irq, that may be shared between channels */ |
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 95ff186f0ccd..10ee22ae5c15 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c | |||
@@ -700,6 +700,14 @@ void ata_bmdma_freeze(struct ata_port *ap) | |||
700 | writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); | 700 | writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); |
701 | else | 701 | else |
702 | outb(ap->ctl, ioaddr->ctl_addr); | 702 | outb(ap->ctl, ioaddr->ctl_addr); |
703 | |||
704 | /* Under certain circumstances, some controllers raise IRQ on | ||
705 | * ATA_NIEN manipulation. Also, many controllers fail to mask | ||
706 | * previously pending IRQ on ATA_NIEN assertion. Clear it. | ||
707 | */ | ||
708 | ata_chk_status(ap); | ||
709 | |||
710 | ap->ops->irq_clear(ap); | ||
703 | } | 711 | } |
704 | 712 | ||
705 | /** | 713 | /** |