aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-07-20 10:20:01 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-08-01 19:46:39 -0400
commit213373cf974fe69e78ec894b07f45ae2f5a3a078 (patch)
tree9e25256c54df4dfe7664e7bd6c45b55f99cfea66 /drivers/ata
parent4d1f9082251a835ea387b47bb9dd26980bf8e0d0 (diff)
ata_piix: fix locking around SIDPR access
SIDPR window registers are shared across ports and as each access is done in two steps, accesses to different ports under EH may race. This primarily is caused by incorrect host locking in EH context and should be fixed by defining locking requirements for each EH operation which can be used during EH and enforcing them but for now work around the problem by adding a dedicated SIDPR lock and grabbing it for each SIDPR access. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Mark Knecht <markknecht@gmail.com> Reported-by: Paul Check <paul@thechecks.ca> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ata_piix.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 7409f98d2ae6..3971bc0a4838 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -158,6 +158,7 @@ struct piix_map_db {
158struct piix_host_priv { 158struct piix_host_priv {
159 const int *map; 159 const int *map;
160 u32 saved_iocfg; 160 u32 saved_iocfg;
161 spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */
161 void __iomem *sidpr; 162 void __iomem *sidpr;
162}; 163};
163 164
@@ -951,12 +952,15 @@ static int piix_sidpr_scr_read(struct ata_link *link,
951 unsigned int reg, u32 *val) 952 unsigned int reg, u32 *val)
952{ 953{
953 struct piix_host_priv *hpriv = link->ap->host->private_data; 954 struct piix_host_priv *hpriv = link->ap->host->private_data;
955 unsigned long flags;
954 956
955 if (reg >= ARRAY_SIZE(piix_sidx_map)) 957 if (reg >= ARRAY_SIZE(piix_sidx_map))
956 return -EINVAL; 958 return -EINVAL;
957 959
960 spin_lock_irqsave(&hpriv->sidpr_lock, flags);
958 piix_sidpr_sel(link, reg); 961 piix_sidpr_sel(link, reg);
959 *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); 962 *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
963 spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
960 return 0; 964 return 0;
961} 965}
962 966
@@ -964,12 +968,15 @@ static int piix_sidpr_scr_write(struct ata_link *link,
964 unsigned int reg, u32 val) 968 unsigned int reg, u32 val)
965{ 969{
966 struct piix_host_priv *hpriv = link->ap->host->private_data; 970 struct piix_host_priv *hpriv = link->ap->host->private_data;
971 unsigned long flags;
967 972
968 if (reg >= ARRAY_SIZE(piix_sidx_map)) 973 if (reg >= ARRAY_SIZE(piix_sidx_map))
969 return -EINVAL; 974 return -EINVAL;
970 975
976 spin_lock_irqsave(&hpriv->sidpr_lock, flags);
971 piix_sidpr_sel(link, reg); 977 piix_sidpr_sel(link, reg);
972 iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); 978 iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
979 spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
973 return 0; 980 return 0;
974} 981}
975 982
@@ -1566,6 +1573,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
1566 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 1573 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
1567 if (!hpriv) 1574 if (!hpriv)
1568 return -ENOMEM; 1575 return -ENOMEM;
1576 spin_lock_init(&hpriv->sidpr_lock);
1569 1577
1570 /* Save IOCFG, this will be used for cable detection, quirk 1578 /* Save IOCFG, this will be used for cable detection, quirk
1571 * detection and restoration on detach. This is necessary 1579 * detection and restoration on detach. This is necessary