diff options
author | Mark Lord <liml@rtr.ca> | 2009-04-06 12:30:43 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2009-04-06 20:13:35 -0400 |
commit | 933cb8e5fcdebd4b666165e3f039f814d62b0e52 (patch) | |
tree | b9ebdf51d740e9844876a04bd742a8b33eab2a89 /drivers/ata/sata_mv.c | |
parent | 44c65d169c5d2e5c872581ebc65f12710d7c3b71 (diff) |
sata_mv: fix irq mask races
Prevent racing on the main interrupt mask during port_start and port_stop.
Otherwise, we end up with IRQs masked on inactive ports,
and hotplug insertions then get missed later on.
Found while debugging (out of tree) target mode operations,
but the bug is present and impacting mainline as well.
This patch should also be considered for -stable.
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 | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index be9ae4fc5cbe..8245c82505cc 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -1575,6 +1575,7 @@ static int mv_port_start(struct ata_port *ap) | |||
1575 | struct device *dev = ap->host->dev; | 1575 | struct device *dev = ap->host->dev; |
1576 | struct mv_host_priv *hpriv = ap->host->private_data; | 1576 | struct mv_host_priv *hpriv = ap->host->private_data; |
1577 | struct mv_port_priv *pp; | 1577 | struct mv_port_priv *pp; |
1578 | unsigned long flags; | ||
1578 | int tag; | 1579 | int tag; |
1579 | 1580 | ||
1580 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); | 1581 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); |
@@ -1610,8 +1611,12 @@ static int mv_port_start(struct ata_port *ap) | |||
1610 | pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0]; | 1611 | pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0]; |
1611 | } | 1612 | } |
1612 | } | 1613 | } |
1614 | |||
1615 | spin_lock_irqsave(ap->lock, flags); | ||
1613 | mv_save_cached_regs(ap); | 1616 | mv_save_cached_regs(ap); |
1614 | mv_edma_cfg(ap, 0, 0); | 1617 | mv_edma_cfg(ap, 0, 0); |
1618 | spin_unlock_irqrestore(ap->lock, flags); | ||
1619 | |||
1615 | return 0; | 1620 | return 0; |
1616 | 1621 | ||
1617 | out_port_free_dma_mem: | 1622 | out_port_free_dma_mem: |
@@ -1630,8 +1635,12 @@ out_port_free_dma_mem: | |||
1630 | */ | 1635 | */ |
1631 | static void mv_port_stop(struct ata_port *ap) | 1636 | static void mv_port_stop(struct ata_port *ap) |
1632 | { | 1637 | { |
1638 | unsigned long flags; | ||
1639 | |||
1640 | spin_lock_irqsave(ap->lock, flags); | ||
1633 | mv_stop_edma(ap); | 1641 | mv_stop_edma(ap); |
1634 | mv_enable_port_irqs(ap, 0); | 1642 | mv_enable_port_irqs(ap, 0); |
1643 | spin_unlock_irqrestore(ap->lock, flags); | ||
1635 | mv_port_free_dma_mem(ap); | 1644 | mv_port_free_dma_mem(ap); |
1636 | } | 1645 | } |
1637 | 1646 | ||