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 | |
| 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>
| -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. |
