mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
platform/x86/intel/vsec: Fix enable_cnt imbalance on PCIe error recovery
After a PCIe Uncorrectable Error has been reported by a device with Intel Vendor Specific Extended Capabilities and has been recovered through a Secondary Bus Reset, its driver calls intel_vsec_pci_probe() to rescan and reinitialize VSECs. intel_vsec_pci_probe() invokes pcim_enable_device() and thereby adds another devm action which calls pcim_disable_device() on driver unbind. So once the driver unbinds, pcim_disable_device() will be called as many times as an Uncorrectable Error occurred, plus one. This will lead to an enable_cnt imbalance on driver unbind. Additionally, since commitdc957ab6aa("platform/x86/intel/vsec: Add private data for per-device data"), a devm_kzalloc() allocation is leaked on every Uncorrectable Error. Avoid by splitting the VSEC rescan out of intel_vsec_pci_probe() into a separate helper and calling that on PCIe error recovery. Fixes:936874b77d("platform/x86/intel/vsec: Add PCI error recovery support to Intel PMT") Signed-off-by: Lukas Wunner <lukas@wunner.de> Cc: stable@vger.kernel.org # v6.0+ Link: https://patch.msgid.link/bd594d09fa866dc51dddc9a447c3b23f9b1402cc.1778736835.git.lukas@wunner.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
parent
26cbe119f9
commit
348ccc754d
|
|
@ -649,29 +649,13 @@ static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
static int intel_vsec_pci_init(struct pci_dev *pdev)
|
||||
{
|
||||
const struct intel_vsec_platform_info *info;
|
||||
struct vsec_priv *priv;
|
||||
int num_caps, ret;
|
||||
struct vsec_priv *priv = pci_get_drvdata(pdev);
|
||||
const struct intel_vsec_platform_info *info = priv->info;
|
||||
int run_once = 0;
|
||||
bool found_any = false;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_save_state(pdev);
|
||||
info = (const struct intel_vsec_platform_info *)id->driver_data;
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->info = info;
|
||||
pci_set_drvdata(pdev, priv);
|
||||
int num_caps;
|
||||
|
||||
num_caps = hweight_long(info->caps);
|
||||
while (num_caps--) {
|
||||
|
|
@ -692,6 +676,31 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct intel_vsec_platform_info *info;
|
||||
struct vsec_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_save_state(pdev);
|
||||
info = (const struct intel_vsec_platform_info *)id->driver_data;
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->info = info;
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
return intel_vsec_pci_init(pdev);
|
||||
}
|
||||
|
||||
int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
|
||||
struct intel_vsec_device *vsec_dev)
|
||||
{
|
||||
|
|
@ -832,7 +841,6 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
|
|||
{
|
||||
struct intel_vsec_device *intel_vsec_dev;
|
||||
pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT;
|
||||
const struct pci_device_id *pci_dev_id;
|
||||
unsigned long index;
|
||||
|
||||
dev_info(&pdev->dev, "Resetting PCI slot\n");
|
||||
|
|
@ -853,10 +861,8 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
|
|||
devm_release_action(&pdev->dev, intel_vsec_remove_aux,
|
||||
&intel_vsec_dev->auxdev);
|
||||
}
|
||||
pci_disable_device(pdev);
|
||||
pci_restore_state(pdev);
|
||||
pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev);
|
||||
intel_vsec_pci_probe(pdev, pci_dev_id);
|
||||
intel_vsec_pci_init(pdev);
|
||||
|
||||
out:
|
||||
return status;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user