aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/iov.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2011-11-04 04:45:59 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-01-06 15:10:33 -0500
commitfb51ccbf217c1c994607b6519c7d85250928553d (patch)
treed08ba9a0278da0e75b6c6714e9453e46068e27b4 /drivers/pci/iov.c
parentae5cd86455381282ece162966183d3f208c6fad7 (diff)
PCI: Rework config space blocking services
pci_block_user_cfg_access was designed for the use case that a single context, the IPR driver, temporarily delays user space accesses to the config space via sysfs. This assumption became invalid by the time pci_dev_reset was added as locking instance. Today, if you run two loops in parallel that reset the same device via sysfs, you end up with a kernel BUG as pci_block_user_cfg_access detect the broken assumption. This reworks the pci_block_user_cfg_access to a sleeping service pci_cfg_access_lock and an atomic-compatible variant called pci_cfg_access_trylock. The former not only blocks user space access as before but also waits if access was already locked. The latter service just returns false in this case, allowing the caller to resolve the conflict instead of raising a BUG. Adaptions of the ipr driver were originally written by Brian King. Acked-by: Brian King <brking@linux.vnet.ibm.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/iov.c')
-rw-r--r--drivers/pci/iov.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 1969a3ee3058..6a4d70386a3d 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -348,10 +348,10 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
348 } 348 }
349 349
350 iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; 350 iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
351 pci_block_user_cfg_access(dev); 351 pci_cfg_access_lock(dev);
352 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 352 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
353 msleep(100); 353 msleep(100);
354 pci_unblock_user_cfg_access(dev); 354 pci_cfg_access_unlock(dev);
355 355
356 iov->initial = initial; 356 iov->initial = initial;
357 if (nr_virtfn < initial) 357 if (nr_virtfn < initial)
@@ -379,10 +379,10 @@ failed:
379 virtfn_remove(dev, j, 0); 379 virtfn_remove(dev, j, 0);
380 380
381 iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 381 iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
382 pci_block_user_cfg_access(dev); 382 pci_cfg_access_lock(dev);
383 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 383 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
384 ssleep(1); 384 ssleep(1);
385 pci_unblock_user_cfg_access(dev); 385 pci_cfg_access_unlock(dev);
386 386
387 if (iov->link != dev->devfn) 387 if (iov->link != dev->devfn)
388 sysfs_remove_link(&dev->dev.kobj, "dep_link"); 388 sysfs_remove_link(&dev->dev.kobj, "dep_link");
@@ -405,10 +405,10 @@ static void sriov_disable(struct pci_dev *dev)
405 virtfn_remove(dev, i, 0); 405 virtfn_remove(dev, i, 0);
406 406
407 iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 407 iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
408 pci_block_user_cfg_access(dev); 408 pci_cfg_access_lock(dev);
409 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 409 pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
410 ssleep(1); 410 ssleep(1);
411 pci_unblock_user_cfg_access(dev); 411 pci_cfg_access_unlock(dev);
412 412
413 if (iov->link != dev->devfn) 413 if (iov->link != dev->devfn)
414 sysfs_remove_link(&dev->dev.kobj, "dep_link"); 414 sysfs_remove_link(&dev->dev.kobj, "dep_link");