diff options
author | Mark Lord <liml@rtr.ca> | 2008-05-17 13:38:00 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-19 17:30:11 -0400 |
commit | 96e2c487933e5f69e98fffdcae2c35c78a671c07 (patch) | |
tree | 418ff66ed6e6aaaef8775e1b6d03d6c799fc6b4c /drivers/ata/sata_mv.c | |
parent | a44253d24a97ec3efe601267274a5fb64d8696c1 (diff) |
sata_mv: cache main_irq_mask register in hpriv
Part five of simplifying/fixing handling of the main_irq_mask register
to resolve unexpected interrupt issues observed in 2.6.26-rc*.
Keep a cached copy of the main_irq_mask so that we don't have
to stall the CPU to read it on every pass through mv_interrupt.
This significantly speeds up interrupt handling, both for sata_mv,
and for any other driver/device sharing the same PCI IRQ line.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r-- | drivers/ata/sata_mv.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index eb7f3dafb502..2d8a7e894b7b 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -458,6 +458,7 @@ struct mv_port_signal { | |||
458 | 458 | ||
459 | struct mv_host_priv { | 459 | struct mv_host_priv { |
460 | u32 hp_flags; | 460 | u32 hp_flags; |
461 | u32 main_irq_mask; | ||
461 | struct mv_port_signal signal[8]; | 462 | struct mv_port_signal signal[8]; |
462 | const struct mv_hw_ops *ops; | 463 | const struct mv_hw_ops *ops; |
463 | int n_ports; | 464 | int n_ports; |
@@ -843,10 +844,12 @@ static void mv_set_main_irq_mask(struct ata_host *host, | |||
843 | struct mv_host_priv *hpriv = host->private_data; | 844 | struct mv_host_priv *hpriv = host->private_data; |
844 | u32 old_mask, new_mask; | 845 | u32 old_mask, new_mask; |
845 | 846 | ||
846 | old_mask = readl(hpriv->main_irq_mask_addr); | 847 | old_mask = hpriv->main_irq_mask; |
847 | new_mask = (old_mask & ~disable_bits) | enable_bits; | 848 | new_mask = (old_mask & ~disable_bits) | enable_bits; |
848 | if (new_mask != old_mask) | 849 | if (new_mask != old_mask) { |
850 | hpriv->main_irq_mask = new_mask; | ||
849 | writelfl(new_mask, hpriv->main_irq_mask_addr); | 851 | writelfl(new_mask, hpriv->main_irq_mask_addr); |
852 | } | ||
850 | } | 853 | } |
851 | 854 | ||
852 | static void mv_enable_port_irqs(struct ata_port *ap, | 855 | static void mv_enable_port_irqs(struct ata_port *ap, |
@@ -2200,12 +2203,11 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) | |||
2200 | struct ata_host *host = dev_instance; | 2203 | struct ata_host *host = dev_instance; |
2201 | struct mv_host_priv *hpriv = host->private_data; | 2204 | struct mv_host_priv *hpriv = host->private_data; |
2202 | unsigned int handled = 0; | 2205 | unsigned int handled = 0; |
2203 | u32 main_irq_cause, main_irq_mask, pending_irqs; | 2206 | u32 main_irq_cause, pending_irqs; |
2204 | 2207 | ||
2205 | spin_lock(&host->lock); | 2208 | spin_lock(&host->lock); |
2206 | main_irq_cause = readl(hpriv->main_irq_cause_addr); | 2209 | main_irq_cause = readl(hpriv->main_irq_cause_addr); |
2207 | main_irq_mask = readl(hpriv->main_irq_mask_addr); | 2210 | pending_irqs = main_irq_cause & hpriv->main_irq_mask; |
2208 | pending_irqs = main_irq_cause & main_irq_mask; | ||
2209 | /* | 2211 | /* |
2210 | * Deal with cases where we either have nothing pending, or have read | 2212 | * Deal with cases where we either have nothing pending, or have read |
2211 | * a bogus register value which can indicate HW removal or PCI fault. | 2213 | * a bogus register value which can indicate HW removal or PCI fault. |