diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2011-11-04 04:45:59 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-01-06 15:10:33 -0500 |
commit | fb51ccbf217c1c994607b6519c7d85250928553d (patch) | |
tree | d08ba9a0278da0e75b6c6714e9453e46068e27b4 /drivers/pci/iov.c | |
parent | ae5cd86455381282ece162966183d3f208c6fad7 (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.c | 12 |
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"); |