Merge branch 'pci/virtualization' into next
* pci/virtualization: PCI: Remove __pci_dev_reset() and pci_dev_reset() PCI: Split ->reset_notify() method into ->reset_prepare() and ->reset_done() PCI: Protect pci_error_handlers->reset_notify() usage with device_lock() PCI: Protect pci_driver->sriov_configure() usage with device_lock() PCI: Mark Intel XXV710 NIC INTx masking as broken PCI: Restore PRI and PASID state after Function-Level Reset PCI: Cache PRI and PASID bits in pci_dev
This commit is contained in:
@@ -153,23 +153,27 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
|
||||
u32 max_requests;
|
||||
int pos;
|
||||
|
||||
if (WARN_ON(pdev->pri_enabled))
|
||||
return -EBUSY;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
|
||||
if ((control & PCI_PRI_CTRL_ENABLE) ||
|
||||
!(status & PCI_PRI_STATUS_STOPPED))
|
||||
if (!(status & PCI_PRI_STATUS_STOPPED))
|
||||
return -EBUSY;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
|
||||
reqs = min(max_requests, reqs);
|
||||
pdev->pri_reqs_alloc = reqs;
|
||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
|
||||
|
||||
control |= PCI_PRI_CTRL_ENABLE;
|
||||
control = PCI_PRI_CTRL_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
|
||||
pdev->pri_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_enable_pri);
|
||||
@@ -185,6 +189,9 @@ void pci_disable_pri(struct pci_dev *pdev)
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
if (WARN_ON(!pdev->pri_enabled))
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return;
|
||||
@@ -192,9 +199,33 @@ void pci_disable_pri(struct pci_dev *pdev)
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
control &= ~PCI_PRI_CTRL_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
|
||||
pdev->pri_enabled = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pri);
|
||||
|
||||
/**
|
||||
* pci_restore_pri_state - Restore PRI
|
||||
* @pdev: PCI device structure
|
||||
*/
|
||||
void pci_restore_pri_state(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control = PCI_PRI_CTRL_ENABLE;
|
||||
u32 reqs = pdev->pri_reqs_alloc;
|
||||
int pos;
|
||||
|
||||
if (!pdev->pri_enabled)
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_restore_pri_state);
|
||||
|
||||
/**
|
||||
* pci_reset_pri - Resets device's PRI state
|
||||
* @pdev: PCI device structure
|
||||
@@ -207,16 +238,14 @@ int pci_reset_pri(struct pci_dev *pdev)
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
if (WARN_ON(pdev->pri_enabled))
|
||||
return -EBUSY;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
if (control & PCI_PRI_CTRL_ENABLE)
|
||||
return -EBUSY;
|
||||
|
||||
control |= PCI_PRI_CTRL_RESET;
|
||||
|
||||
control = PCI_PRI_CTRL_RESET;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
|
||||
return 0;
|
||||
@@ -239,16 +268,14 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
|
||||
u16 control, supported;
|
||||
int pos;
|
||||
|
||||
if (WARN_ON(pdev->pasid_enabled))
|
||||
return -EBUSY;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
|
||||
|
||||
if (control & PCI_PASID_CTRL_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
||||
|
||||
/* User wants to enable anything unsupported? */
|
||||
@@ -256,9 +283,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
|
||||
return -EINVAL;
|
||||
|
||||
control = PCI_PASID_CTRL_ENABLE | features;
|
||||
pdev->pasid_features = features;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
|
||||
|
||||
pdev->pasid_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_enable_pasid);
|
||||
@@ -266,21 +296,46 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid);
|
||||
/**
|
||||
* pci_disable_pasid - Disable the PASID capability
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
*/
|
||||
void pci_disable_pasid(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control = 0;
|
||||
int pos;
|
||||
|
||||
if (WARN_ON(!pdev->pasid_enabled))
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
|
||||
|
||||
pdev->pasid_enabled = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
||||
|
||||
/**
|
||||
* pci_restore_pasid_state - Restore PASID capabilities
|
||||
* @pdev: PCI device structure
|
||||
*/
|
||||
void pci_restore_pasid_state(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
if (!pdev->pasid_enabled)
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
|
||||
|
||||
/**
|
||||
* pci_pasid_features - Check which PASID features are supported
|
||||
* @pdev: PCI device structure
|
||||
|
@@ -461,8 +461,6 @@ found:
|
||||
else
|
||||
iov->dev = dev;
|
||||
|
||||
mutex_init(&iov->lock);
|
||||
|
||||
dev->sriov = iov;
|
||||
dev->is_physfn = 1;
|
||||
rc = compute_max_vf_buses(dev);
|
||||
@@ -491,8 +489,6 @@ static void sriov_release(struct pci_dev *dev)
|
||||
if (dev != dev->sriov->dev)
|
||||
pci_dev_put(dev->sriov->dev);
|
||||
|
||||
mutex_destroy(&dev->sriov->lock);
|
||||
|
||||
kfree(dev->sriov);
|
||||
dev->sriov = NULL;
|
||||
}
|
||||
|
@@ -595,7 +595,6 @@ static ssize_t sriov_numvfs_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pci_sriov *iov = pdev->sriov;
|
||||
int ret;
|
||||
u16 num_vfs;
|
||||
|
||||
@@ -606,7 +605,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
|
||||
if (num_vfs > pci_sriov_get_totalvfs(pdev))
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&iov->dev->sriov->lock);
|
||||
device_lock(&pdev->dev);
|
||||
|
||||
if (num_vfs == pdev->sriov->num_VFs)
|
||||
goto exit;
|
||||
@@ -641,7 +640,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
|
||||
num_vfs, ret);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&iov->dev->sriov->lock);
|
||||
device_unlock(&pdev->dev);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pci-ats.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/dma.h>
|
||||
#include <linux/aer.h>
|
||||
@@ -1173,6 +1174,8 @@ void pci_restore_state(struct pci_dev *dev)
|
||||
|
||||
/* PCI Express register must be restored first */
|
||||
pci_restore_pcie_state(dev);
|
||||
pci_restore_pasid_state(dev);
|
||||
pci_restore_pri_state(dev);
|
||||
pci_restore_ats_state(dev);
|
||||
pci_restore_vc_state(dev);
|
||||
|
||||
@@ -4033,40 +4036,6 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
|
||||
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
|
||||
}
|
||||
|
||||
static int __pci_dev_reset(struct pci_dev *dev, int probe)
|
||||
{
|
||||
int rc;
|
||||
|
||||
might_sleep();
|
||||
|
||||
rc = pci_dev_specific_reset(dev, probe);
|
||||
if (rc != -ENOTTY)
|
||||
goto done;
|
||||
|
||||
if (pcie_has_flr(dev)) {
|
||||
if (!probe)
|
||||
pcie_flr(dev);
|
||||
rc = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = pci_af_flr(dev, probe);
|
||||
if (rc != -ENOTTY)
|
||||
goto done;
|
||||
|
||||
rc = pci_pm_reset(dev, probe);
|
||||
if (rc != -ENOTTY)
|
||||
goto done;
|
||||
|
||||
rc = pci_dev_reset_slot_function(dev, probe);
|
||||
if (rc != -ENOTTY)
|
||||
goto done;
|
||||
|
||||
rc = pci_parent_bus_reset(dev, probe);
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void pci_dev_lock(struct pci_dev *dev)
|
||||
{
|
||||
pci_cfg_access_lock(dev);
|
||||
@@ -4092,26 +4061,18 @@ static void pci_dev_unlock(struct pci_dev *dev)
|
||||
pci_cfg_access_unlock(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_reset_notify - notify device driver of reset
|
||||
* @dev: device to be notified of reset
|
||||
* @prepare: 'true' if device is about to be reset; 'false' if reset attempt
|
||||
* completed
|
||||
*
|
||||
* Must be called prior to device access being disabled and after device
|
||||
* access is restored.
|
||||
*/
|
||||
static void pci_reset_notify(struct pci_dev *dev, bool prepare)
|
||||
static void pci_dev_save_and_disable(struct pci_dev *dev)
|
||||
{
|
||||
const struct pci_error_handlers *err_handler =
|
||||
dev->driver ? dev->driver->err_handler : NULL;
|
||||
if (err_handler && err_handler->reset_notify)
|
||||
err_handler->reset_notify(dev, prepare);
|
||||
}
|
||||
|
||||
static void pci_dev_save_and_disable(struct pci_dev *dev)
|
||||
{
|
||||
pci_reset_notify(dev, true);
|
||||
/*
|
||||
* dev->driver->err_handler->reset_prepare() is protected against
|
||||
* races with ->remove() by the device lock, which must be held by
|
||||
* the caller.
|
||||
*/
|
||||
if (err_handler && err_handler->reset_prepare)
|
||||
err_handler->reset_prepare(dev);
|
||||
|
||||
/*
|
||||
* Wake-up device prior to save. PM registers default to D0 after
|
||||
@@ -4133,23 +4094,18 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
|
||||
|
||||
static void pci_dev_restore(struct pci_dev *dev)
|
||||
{
|
||||
const struct pci_error_handlers *err_handler =
|
||||
dev->driver ? dev->driver->err_handler : NULL;
|
||||
|
||||
pci_restore_state(dev);
|
||||
pci_reset_notify(dev, false);
|
||||
}
|
||||
|
||||
static int pci_dev_reset(struct pci_dev *dev, int probe)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!probe)
|
||||
pci_dev_lock(dev);
|
||||
|
||||
rc = __pci_dev_reset(dev, probe);
|
||||
|
||||
if (!probe)
|
||||
pci_dev_unlock(dev);
|
||||
|
||||
return rc;
|
||||
/*
|
||||
* dev->driver->err_handler->reset_done() is protected against
|
||||
* races with ->remove() by the device lock, which must be held by
|
||||
* the caller.
|
||||
*/
|
||||
if (err_handler && err_handler->reset_done)
|
||||
err_handler->reset_done(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4171,7 +4127,13 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
|
||||
*/
|
||||
int __pci_reset_function(struct pci_dev *dev)
|
||||
{
|
||||
return pci_dev_reset(dev, 0);
|
||||
int ret;
|
||||
|
||||
pci_dev_lock(dev);
|
||||
ret = __pci_reset_function_locked(dev);
|
||||
pci_dev_unlock(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pci_reset_function);
|
||||
|
||||
@@ -4196,7 +4158,27 @@ EXPORT_SYMBOL_GPL(__pci_reset_function);
|
||||
*/
|
||||
int __pci_reset_function_locked(struct pci_dev *dev)
|
||||
{
|
||||
return __pci_dev_reset(dev, 0);
|
||||
int rc;
|
||||
|
||||
might_sleep();
|
||||
|
||||
rc = pci_dev_specific_reset(dev, 0);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
if (pcie_has_flr(dev)) {
|
||||
pcie_flr(dev);
|
||||
return 0;
|
||||
}
|
||||
rc = pci_af_flr(dev, 0);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
rc = pci_pm_reset(dev, 0);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
rc = pci_dev_reset_slot_function(dev, 0);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
return pci_parent_bus_reset(dev, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
|
||||
|
||||
@@ -4213,7 +4195,26 @@ EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
|
||||
*/
|
||||
int pci_probe_reset_function(struct pci_dev *dev)
|
||||
{
|
||||
return pci_dev_reset(dev, 1);
|
||||
int rc;
|
||||
|
||||
might_sleep();
|
||||
|
||||
rc = pci_dev_specific_reset(dev, 1);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
if (pcie_has_flr(dev))
|
||||
return 0;
|
||||
rc = pci_af_flr(dev, 1);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
rc = pci_pm_reset(dev, 1);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
rc = pci_dev_reset_slot_function(dev, 1);
|
||||
if (rc != -ENOTTY)
|
||||
return rc;
|
||||
|
||||
return pci_parent_bus_reset(dev, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4236,15 +4237,17 @@ int pci_reset_function(struct pci_dev *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_dev_reset(dev, 1);
|
||||
rc = pci_probe_reset_function(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_dev_lock(dev);
|
||||
pci_dev_save_and_disable(dev);
|
||||
|
||||
rc = pci_dev_reset(dev, 0);
|
||||
rc = __pci_reset_function_locked(dev);
|
||||
|
||||
pci_dev_restore(dev);
|
||||
pci_dev_unlock(dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -4260,20 +4263,18 @@ int pci_try_reset_function(struct pci_dev *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_dev_reset(dev, 1);
|
||||
rc = pci_probe_reset_function(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_dev_save_and_disable(dev);
|
||||
if (!pci_dev_trylock(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
if (pci_dev_trylock(dev)) {
|
||||
rc = __pci_dev_reset(dev, 0);
|
||||
pci_dev_unlock(dev);
|
||||
} else
|
||||
rc = -EAGAIN;
|
||||
pci_dev_save_and_disable(dev);
|
||||
rc = __pci_reset_function_locked(dev);
|
||||
pci_dev_unlock(dev);
|
||||
|
||||
pci_dev_restore(dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_try_reset_function);
|
||||
@@ -4423,7 +4424,9 @@ static void pci_bus_save_and_disable(struct pci_bus *bus)
|
||||
struct pci_dev *dev;
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
pci_dev_lock(dev);
|
||||
pci_dev_save_and_disable(dev);
|
||||
pci_dev_unlock(dev);
|
||||
if (dev->subordinate)
|
||||
pci_bus_save_and_disable(dev->subordinate);
|
||||
}
|
||||
@@ -4438,7 +4441,9 @@ static void pci_bus_restore(struct pci_bus *bus)
|
||||
struct pci_dev *dev;
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
pci_dev_lock(dev);
|
||||
pci_dev_restore(dev);
|
||||
pci_dev_unlock(dev);
|
||||
if (dev->subordinate)
|
||||
pci_bus_restore(dev->subordinate);
|
||||
}
|
||||
|
@@ -272,7 +272,6 @@ struct pci_sriov {
|
||||
u16 driver_max_VFs; /* max num VFs driver supports */
|
||||
struct pci_dev *dev; /* lowest numbered PF */
|
||||
struct pci_dev *self; /* this PF */
|
||||
struct mutex lock; /* lock for setting sriov_numvfs in sysfs */
|
||||
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
|
||||
bool drivers_autoprobe; /* auto probing of VFs by driver */
|
||||
};
|
||||
|
@@ -3249,6 +3249,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1588,
|
||||
quirk_broken_intx_masking);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1589,
|
||||
quirk_broken_intx_masking);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x158a,
|
||||
quirk_broken_intx_masking);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x158b,
|
||||
quirk_broken_intx_masking);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d0,
|
||||
quirk_broken_intx_masking);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1,
|
||||
|
Reference in New Issue
Block a user