Commit bb02ce95 authored by Bjorn Helgaas's avatar Bjorn Helgaas

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
parents c781f85b 52354b9d
...@@ -2348,30 +2348,19 @@ static void fm10k_io_resume(struct pci_dev *pdev) ...@@ -2348,30 +2348,19 @@ static void fm10k_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev); netif_device_attach(netdev);
} }
/** static void fm10k_io_reset_prepare(struct pci_dev *pdev)
* fm10k_io_reset_notify - called when PCI function is reset
* @pdev: Pointer to PCI device
*
* This callback is called when the PCI function is reset such as from
* /sys/class/net/<enpX>/device/reset or similar. When prepare is true, it
* means we should prepare for a function reset. If prepare is false, it means
* the function reset just occurred.
*/
static void fm10k_io_reset_notify(struct pci_dev *pdev, bool prepare)
{ {
struct fm10k_intfc *interface = pci_get_drvdata(pdev);
int err = 0;
if (prepare) {
/* warn incase we have any active VF devices */ /* warn incase we have any active VF devices */
if (pci_num_vf(pdev)) if (pci_num_vf(pdev))
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"PCIe FLR may cause issues for any active VF devices\n"); "PCIe FLR may cause issues for any active VF devices\n");
fm10k_prepare_suspend(pci_get_drvdata(pdev));
}
fm10k_prepare_suspend(interface); static void fm10k_io_reset_done(struct pci_dev *pdev)
} else { {
err = fm10k_handle_resume(interface); struct fm10k_intfc *interface = pci_get_drvdata(pdev);
} int err = fm10k_handle_resume(interface);
if (err) { if (err) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
...@@ -2384,7 +2373,8 @@ static const struct pci_error_handlers fm10k_err_handler = { ...@@ -2384,7 +2373,8 @@ static const struct pci_error_handlers fm10k_err_handler = {
.error_detected = fm10k_io_error_detected, .error_detected = fm10k_io_error_detected,
.slot_reset = fm10k_io_slot_reset, .slot_reset = fm10k_io_slot_reset,
.resume = fm10k_io_resume, .resume = fm10k_io_resume,
.reset_notify = fm10k_io_reset_notify, .reset_prepare = fm10k_io_reset_prepare,
.reset_done = fm10k_io_reset_done,
}; };
static struct pci_driver fm10k_driver = { static struct pci_driver fm10k_driver = {
......
...@@ -346,11 +346,13 @@ static const struct pci_device_id mwifiex_ids[] = { ...@@ -346,11 +346,13 @@ static const struct pci_device_id mwifiex_ids[] = {
MODULE_DEVICE_TABLE(pci, mwifiex_ids); MODULE_DEVICE_TABLE(pci, mwifiex_ids);
static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) /*
* Cleanup all software without cleaning anything related to PCIe and HW.
*/
static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
{ {
struct pcie_service_card *card = pci_get_drvdata(pdev); struct pcie_service_card *card = pci_get_drvdata(pdev);
struct mwifiex_adapter *adapter = card->adapter; struct mwifiex_adapter *adapter = card->adapter;
int ret;
if (!adapter) { if (!adapter) {
dev_err(&pdev->dev, "%s: adapter structure is not valid\n", dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
...@@ -359,37 +361,48 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) ...@@ -359,37 +361,48 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
} }
mwifiex_dbg(adapter, INFO, mwifiex_dbg(adapter, INFO,
"%s: vendor=0x%4.04x device=0x%4.04x rev=%d %s\n", "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Pre-FLR\n",
__func__, pdev->vendor, pdev->device, __func__, pdev->vendor, pdev->device, pdev->revision);
pdev->revision,
prepare ? "Pre-FLR" : "Post-FLR");
if (prepare) {
/* Kernel would be performing FLR after this notification.
* Cleanup all software without cleaning anything related to
* PCIe and HW.
*/
mwifiex_shutdown_sw(adapter); mwifiex_shutdown_sw(adapter);
adapter->surprise_removed = true; adapter->surprise_removed = true;
clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
} else { mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
/* Kernel stores and restores PCIe function context before and }
* after performing FLR respectively. Reconfigure the software
* and firmware including firmware redownload /*
* Kernel stores and restores PCIe function context before and after performing
* FLR respectively. Reconfigure the software and firmware including firmware
* redownload.
*/ */
static void mwifiex_pcie_reset_done(struct pci_dev *pdev)
{
struct pcie_service_card *card = pci_get_drvdata(pdev);
struct mwifiex_adapter *adapter = card->adapter;
int ret;
if (!adapter) {
dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
__func__);
return;
}
mwifiex_dbg(adapter, INFO,
"%s: vendor=0x%4.04x device=0x%4.04x rev=%d Post-FLR\n",
__func__, pdev->vendor, pdev->device, pdev->revision);
adapter->surprise_removed = false; adapter->surprise_removed = false;
ret = mwifiex_reinit_sw(adapter); ret = mwifiex_reinit_sw(adapter);
if (ret) { if (ret)
dev_err(&pdev->dev, "reinit failed: %d\n", ret); dev_err(&pdev->dev, "reinit failed: %d\n", ret);
return; else
}
}
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
} }
static const struct pci_error_handlers mwifiex_pcie_err_handler[] = { static const struct pci_error_handlers mwifiex_pcie_err_handler = {
{ .reset_notify = mwifiex_pcie_reset_notify, }, .reset_prepare = mwifiex_pcie_reset_prepare,
.reset_done = mwifiex_pcie_reset_done,
}; };
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -410,7 +423,7 @@ static struct pci_driver __refdata mwifiex_pcie = { ...@@ -410,7 +423,7 @@ static struct pci_driver __refdata mwifiex_pcie = {
}, },
#endif #endif
.shutdown = mwifiex_pcie_shutdown, .shutdown = mwifiex_pcie_shutdown,
.err_handler = mwifiex_pcie_err_handler, .err_handler = &mwifiex_pcie_err_handler,
}; };
/* /*
......
...@@ -2145,14 +2145,14 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2145,14 +2145,14 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return result; return result;
} }
static void nvme_reset_notify(struct pci_dev *pdev, bool prepare) static void nvme_reset_prepare(struct pci_dev *pdev)
{ {
struct nvme_dev *dev = pci_get_drvdata(pdev); nvme_dev_disable(pci_get_drvdata(pdev), false);
}
if (prepare) static void nvme_reset_done(struct pci_dev *pdev)
nvme_dev_disable(dev, false); {
else nvme_reset(pci_get_drvdata(pdev));
nvme_reset(dev);
} }
static void nvme_shutdown(struct pci_dev *pdev) static void nvme_shutdown(struct pci_dev *pdev)
...@@ -2275,7 +2275,8 @@ static const struct pci_error_handlers nvme_err_handler = { ...@@ -2275,7 +2275,8 @@ static const struct pci_error_handlers nvme_err_handler = {
.error_detected = nvme_error_detected, .error_detected = nvme_error_detected,
.slot_reset = nvme_slot_reset, .slot_reset = nvme_slot_reset,
.resume = nvme_error_resume, .resume = nvme_error_resume,
.reset_notify = nvme_reset_notify, .reset_prepare = nvme_reset_prepare,
.reset_done = nvme_reset_done,
}; };
static const struct pci_device_id nvme_id_table[] = { static const struct pci_device_id nvme_id_table[] = {
......
...@@ -153,23 +153,27 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) ...@@ -153,23 +153,27 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
u32 max_requests; u32 max_requests;
int pos; int pos;
if (WARN_ON(pdev->pri_enabled))
return -EBUSY;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos) if (!pos)
return -EINVAL; return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
if ((control & PCI_PRI_CTRL_ENABLE) || if (!(status & PCI_PRI_STATUS_STOPPED))
!(status & PCI_PRI_STATUS_STOPPED))
return -EBUSY; return -EBUSY;
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests); pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
reqs = min(max_requests, reqs); reqs = min(max_requests, reqs);
pdev->pri_reqs_alloc = reqs;
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, 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); pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pdev->pri_enabled = 1;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_enable_pri); EXPORT_SYMBOL_GPL(pci_enable_pri);
...@@ -185,6 +189,9 @@ void pci_disable_pri(struct pci_dev *pdev) ...@@ -185,6 +189,9 @@ void pci_disable_pri(struct pci_dev *pdev)
u16 control; u16 control;
int pos; int pos;
if (WARN_ON(!pdev->pri_enabled))
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos) if (!pos)
return; return;
...@@ -192,9 +199,33 @@ void pci_disable_pri(struct pci_dev *pdev) ...@@ -192,9 +199,33 @@ void pci_disable_pri(struct pci_dev *pdev)
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
control &= ~PCI_PRI_CTRL_ENABLE; control &= ~PCI_PRI_CTRL_ENABLE;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pdev->pri_enabled = 0;
} }
EXPORT_SYMBOL_GPL(pci_disable_pri); 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 * pci_reset_pri - Resets device's PRI state
* @pdev: PCI device structure * @pdev: PCI device structure
...@@ -207,16 +238,14 @@ int pci_reset_pri(struct pci_dev *pdev) ...@@ -207,16 +238,14 @@ int pci_reset_pri(struct pci_dev *pdev)
u16 control; u16 control;
int pos; int pos;
if (WARN_ON(pdev->pri_enabled))
return -EBUSY;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos) if (!pos)
return -EINVAL; return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); control = PCI_PRI_CTRL_RESET;
if (control & PCI_PRI_CTRL_ENABLE)
return -EBUSY;
control |= PCI_PRI_CTRL_RESET;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
return 0; return 0;
...@@ -239,16 +268,14 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) ...@@ -239,16 +268,14 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
u16 control, supported; u16 control, supported;
int pos; int pos;
if (WARN_ON(pdev->pasid_enabled))
return -EBUSY;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos) if (!pos)
return -EINVAL; return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); 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; supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
/* User wants to enable anything unsupported? */ /* User wants to enable anything unsupported? */
...@@ -256,9 +283,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) ...@@ -256,9 +283,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
return -EINVAL; return -EINVAL;
control = PCI_PASID_CTRL_ENABLE | features; control = PCI_PASID_CTRL_ENABLE | features;
pdev->pasid_features = features;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
pdev->pasid_enabled = 1;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_enable_pasid); EXPORT_SYMBOL_GPL(pci_enable_pasid);
...@@ -266,21 +296,46 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid); ...@@ -266,21 +296,46 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid);
/** /**
* pci_disable_pasid - Disable the PASID capability * pci_disable_pasid - Disable the PASID capability
* @pdev: PCI device structure * @pdev: PCI device structure
*
*/ */
void pci_disable_pasid(struct pci_dev *pdev) void pci_disable_pasid(struct pci_dev *pdev)
{ {
u16 control = 0; u16 control = 0;
int pos; int pos;
if (WARN_ON(!pdev->pasid_enabled))
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos) if (!pos)
return; return;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
pdev->pasid_enabled = 0;
} }
EXPORT_SYMBOL_GPL(pci_disable_pasid); 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 * pci_pasid_features - Check which PASID features are supported
* @pdev: PCI device structure * @pdev: PCI device structure
......
...@@ -461,8 +461,6 @@ static int sriov_init(struct pci_dev *dev, int pos) ...@@ -461,8 +461,6 @@ static int sriov_init(struct pci_dev *dev, int pos)
else else
iov->dev = dev; iov->dev = dev;
mutex_init(&iov->lock);
dev->sriov = iov; dev->sriov = iov;
dev->is_physfn = 1; dev->is_physfn = 1;
rc = compute_max_vf_buses(dev); rc = compute_max_vf_buses(dev);
...@@ -491,8 +489,6 @@ static void sriov_release(struct pci_dev *dev) ...@@ -491,8 +489,6 @@ static void sriov_release(struct pci_dev *dev)
if (dev != dev->sriov->dev) if (dev != dev->sriov->dev)
pci_dev_put(dev->sriov->dev); pci_dev_put(dev->sriov->dev);
mutex_destroy(&dev->sriov->lock);
kfree(dev->sriov); kfree(dev->sriov);
dev->sriov = NULL; dev->sriov = NULL;
} }
......
...@@ -595,7 +595,6 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -595,7 +595,6 @@ static ssize_t sriov_numvfs_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct pci_sriov *iov = pdev->sriov;
int ret; int ret;
u16 num_vfs; u16 num_vfs;
...@@ -606,7 +605,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -606,7 +605,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
if (num_vfs > pci_sriov_get_totalvfs(pdev)) if (num_vfs > pci_sriov_get_totalvfs(pdev))
return -ERANGE; return -ERANGE;
mutex_lock(&iov->dev->sriov->lock); device_lock(&pdev->dev);
if (num_vfs == pdev->sriov->num_VFs) if (num_vfs == pdev->sriov->num_VFs)
goto exit; goto exit;
...@@ -641,7 +640,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -641,7 +640,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
num_vfs, ret); num_vfs, ret);
exit: exit:
mutex_unlock(&iov->dev->sriov->lock); device_unlock(&pdev->dev);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/pci-ats.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <linux/aer.h> #include <linux/aer.h>
...@@ -1173,6 +1174,8 @@ void pci_restore_state(struct pci_dev *dev) ...@@ -1173,6 +1174,8 @@ void pci_restore_state(struct pci_dev *dev)
/* PCI Express register must be restored first */ /* PCI Express register must be restored first */
pci_restore_pcie_state(dev); pci_restore_pcie_state(dev);
pci_restore_pasid_state(dev);
pci_restore_pri_state(dev);
pci_restore_ats_state(dev); pci_restore_ats_state(dev);
pci_restore_vc_state(dev); pci_restore_vc_state(dev);
...@@ -4033,40 +4036,6 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) ...@@ -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); 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) static void pci_dev_lock(struct pci_dev *dev)
{ {
pci_cfg_access_lock(dev); pci_cfg_access_lock(dev);
...@@ -4092,26 +4061,18 @@ static void pci_dev_unlock(struct pci_dev *dev) ...@@ -4092,26 +4061,18 @@ static void pci_dev_unlock(struct pci_dev *dev)
pci_cfg_access_unlock(dev); pci_cfg_access_unlock(dev);
} }
/** static void pci_dev_save_and_disable(struct pci_dev *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)
{ {
const struct pci_error_handlers *err_handler = const struct pci_error_handlers *err_handler =
dev->driver ? dev->driver->err_handler : NULL; 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) /*
{ * dev->driver->err_handler->reset_prepare() is protected against
pci_reset_notify(dev, true); * 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 * 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) ...@@ -4133,23 +4094,18 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
static void pci_dev_restore(struct pci_dev *dev) static void pci_dev_restore(struct pci_dev *dev)
{ {
pci_restore_state(dev); const struct pci_error_handlers *err_handler =
pci_reset_notify(dev, false); dev->driver ? dev->driver->err_handler : NULL;
}
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_restore_state(dev);
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) ...@@ -4171,7 +4127,13 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
*/ */
int __pci_reset_function(struct pci_dev *dev) 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); EXPORT_SYMBOL_GPL(__pci_reset_function);
...@@ -4196,7 +4158,27 @@ 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) 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); EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
...@@ -4213,7 +4195,26 @@ 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) 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) ...@@ -4236,15 +4237,17 @@ int pci_reset_function(struct pci_dev *dev)
{ {
int rc; int rc;
rc = pci_dev_reset(dev, 1); rc = pci_probe_reset_function(dev);
if (rc) if (rc)
return rc; return rc;
pci_dev_lock(dev);
pci_dev_save_and_disable(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_restore(dev);
pci_dev_unlock(dev);
return rc; return rc;
} }
...@@ -4260,20 +4263,18 @@ int pci_try_reset_function(struct pci_dev *dev) ...@@ -4260,20 +4263,18 @@ int pci_try_reset_function(struct pci_dev *dev)
{ {
int rc; int rc;
rc = pci_dev_reset(dev, 1); rc = pci_probe_reset_function(dev);
if (rc) if (rc)
return rc; return rc;
pci_dev_save_and_disable(dev); if (!pci_dev_trylock(dev))
return -EAGAIN;
if (pci_dev_trylock(dev)) { pci_dev_save_and_disable(dev);
rc = __pci_dev_reset(dev, 0); rc = __pci_reset_function_locked(dev);
pci_dev_unlock(dev); pci_dev_unlock(dev);
} else
rc = -EAGAIN;
pci_dev_restore(dev); pci_dev_restore(dev);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(pci_try_reset_function); EXPORT_SYMBOL_GPL(pci_try_reset_function);
...@@ -4423,7 +4424,9 @@ static void pci_bus_save_and_disable(struct pci_bus *bus) ...@@ -4423,7 +4424,9 @@ static void pci_bus_save_and_disable(struct pci_bus *bus)
struct pci_dev *dev; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
pci_dev_lock(dev);
pci_dev_save_and_disable(dev); pci_dev_save_and_disable(dev);
pci_dev_unlock(dev);
if (dev->subordinate) if (dev->subordinate)
pci_bus_save_and_disable(dev->subordinate); pci_bus_save_and_disable(dev->subordinate);
} }
...@@ -4438,7 +4441,9 @@ static void pci_bus_restore(struct pci_bus *bus) ...@@ -4438,7 +4441,9 @@ static void pci_bus_restore(struct pci_bus *bus)
struct pci_dev *dev; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
pci_dev_lock(dev);
pci_dev_restore(dev); pci_dev_restore(dev);
pci_dev_unlock(dev);
if (dev->subordinate) if (dev->subordinate)
pci_bus_restore(dev->subordinate); pci_bus_restore(dev->subordinate);
} }
......
...@@ -272,7 +272,6 @@ struct pci_sriov { ...@@ -272,7 +272,6 @@ struct pci_sriov {
u16 driver_max_VFs; /* max num VFs driver supports */ u16 driver_max_VFs; /* max num VFs driver supports */
struct pci_dev *dev; /* lowest numbered PF */ struct pci_dev *dev; /* lowest numbered PF */
struct pci_dev *self; /* this 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 */ resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
bool drivers_autoprobe; /* auto probing of VFs by driver */ bool drivers_autoprobe; /* auto probing of VFs by driver */
}; };
......
...@@ -3249,6 +3249,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1588, ...@@ -3249,6 +3249,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1588,
quirk_broken_intx_masking); quirk_broken_intx_masking);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1589, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1589,
quirk_broken_intx_masking); 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, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d0,
quirk_broken_intx_masking); quirk_broken_intx_masking);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
int pci_enable_pri(struct pci_dev *pdev, u32 reqs); int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
void pci_disable_pri(struct pci_dev *pdev); void pci_disable_pri(struct pci_dev *pdev);
void pci_restore_pri_state(struct pci_dev *pdev);
int pci_reset_pri(struct pci_dev *pdev); int pci_reset_pri(struct pci_dev *pdev);
#else /* CONFIG_PCI_PRI */ #else /* CONFIG_PCI_PRI */
...@@ -20,6 +21,10 @@ static inline void pci_disable_pri(struct pci_dev *pdev) ...@@ -20,6 +21,10 @@ static inline void pci_disable_pri(struct pci_dev *pdev)
{ {
} }
static inline void pci_restore_pri_state(struct pci_dev *pdev)
{
}
static inline int pci_reset_pri(struct pci_dev *pdev) static inline int pci_reset_pri(struct pci_dev *pdev)
{ {
return -ENODEV; return -ENODEV;
...@@ -31,6 +36,7 @@ static inline int pci_reset_pri(struct pci_dev *pdev) ...@@ -31,6 +36,7 @@ static inline int pci_reset_pri(struct pci_dev *pdev)
int pci_enable_pasid(struct pci_dev *pdev, int features); int pci_enable_pasid(struct pci_dev *pdev, int features);
void pci_disable_pasid(struct pci_dev *pdev); void pci_disable_pasid(struct pci_dev *pdev);
void pci_restore_pasid_state(struct pci_dev *pdev);
int pci_pasid_features(struct pci_dev *pdev); int pci_pasid_features(struct pci_dev *pdev);
int pci_max_pasids(struct pci_dev *pdev); int pci_max_pasids(struct pci_dev *pdev);
...@@ -45,6 +51,10 @@ static inline void pci_disable_pasid(struct pci_dev *pdev) ...@@ -45,6 +51,10 @@ static inline void pci_disable_pasid(struct pci_dev *pdev)
{ {
} }
static inline void pci_restore_pasid_state(struct pci_dev *pdev)
{
}
static inline int pci_pasid_features(struct pci_dev *pdev) static inline int pci_pasid_features(struct pci_dev *pdev)
{ {
return -EINVAL; return -EINVAL;
......
...@@ -361,6 +361,8 @@ struct pci_dev { ...@@ -361,6 +361,8 @@ struct pci_dev {
unsigned int msix_enabled:1; unsigned int msix_enabled:1;
unsigned int ari_enabled:1; /* ARI forwarding */ unsigned int ari_enabled:1; /* ARI forwarding */
unsigned int ats_enabled:1; /* Address Translation Service */ unsigned int ats_enabled:1; /* Address Translation Service */
unsigned int pasid_enabled:1; /* Process Address Space ID */
unsigned int pri_enabled:1; /* Page Request Interface */
unsigned int is_managed:1; unsigned int is_managed:1;
unsigned int needs_freset:1; /* Dev requires fundamental reset */ unsigned int needs_freset:1; /* Dev requires fundamental reset */
unsigned int state_saved:1; unsigned int state_saved:1;
...@@ -403,6 +405,12 @@ struct pci_dev { ...@@ -403,6 +405,12 @@ struct pci_dev {
u16 ats_cap; /* ATS Capability offset */ u16 ats_cap; /* ATS Capability offset */
u8 ats_stu; /* ATS Smallest Translation Unit */ u8 ats_stu; /* ATS Smallest Translation Unit */
atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */ atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
#endif
#ifdef CONFIG_PCI_PRI
u32 pri_reqs_alloc; /* Number of PRI requests allocated */
#endif
#ifdef CONFIG_PCI_PASID
u16 pasid_features;
#endif #endif
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
size_t romlen; /* Length of ROM if it's not from the BAR */ size_t romlen; /* Length of ROM if it's not from the BAR */
...@@ -695,7 +703,8 @@ struct pci_error_handlers { ...@@ -695,7 +703,8 @@ struct pci_error_handlers {
pci_ers_result_t (*slot_reset)(struct pci_dev *dev); pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
/* PCI function reset prepare or completed */ /* PCI function reset prepare or completed */
void (*reset_notify)(struct pci_dev *dev, bool prepare); void (*reset_prepare)(struct pci_dev *dev);
void (*reset_done)(struct pci_dev *dev);
/* Device driver may resume normal operations */ /* Device driver may resume normal operations */
void (*resume)(struct pci_dev *dev); void (*resume)(struct pci_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment