From 91295d79d65892eabd02a2a75fd4ac88197d17a1 Mon Sep 17 00:00:00 2001
From: Sinan Kaya <okaya@codeaurora.org>
Date: Tue, 27 Feb 2018 14:14:08 -0600
Subject: [PATCH] PCI: Handle FLR failure and allow other reset types
Git-commit: 91295d79d65892eabd02a2a75fd4ac88197d17a1
Patch-mainline: v4.17-rc1
References: FATE#326145
pci_flr_wait() and pci_af_flr() functions assume graceful return even
though the device is inaccessible under error conditions.
Return -ENOTTY in error cases so that __pci_reset_function_locked() can
try other reset types if AF_FLR/FLR reset fails.
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Takashi Iwai <tiwai@suse.de>
---
drivers/pci/pci.c | 18 ++++++++++--------
include/linux/pci.h | 2 +-
2 files changed, 11 insertions(+), 9 deletions(-)
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3946,7 +3946,7 @@ int pci_wait_for_pending_transaction(str
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
-static void pci_flr_wait(struct pci_dev *dev)
+static int pci_flr_wait(struct pci_dev *dev)
{
int delay = 1, timeout = 60000;
u32 id;
@@ -3975,7 +3975,7 @@ static void pci_flr_wait(struct pci_dev
if (delay > timeout) {
pci_warn(dev, "not ready %dms after FLR; giving up\n",
100 + delay - 1);
- return;
+ return -ENOTTY;
}
if (delay > 1000)
@@ -3989,6 +3989,8 @@ static void pci_flr_wait(struct pci_dev
if (delay > 1000)
pci_info(dev, "ready %dms after FLR\n", 100 + delay - 1);
+
+ return 0;
}
/**
@@ -4017,13 +4019,13 @@ static bool pcie_has_flr(struct pci_dev
* device supports FLR before calling this function, e.g. by using the
* pcie_has_flr() helper.
*/
-void pcie_flr(struct pci_dev *dev)
+int pcie_flr(struct pci_dev *dev)
{
if (!pci_wait_for_pending_transaction(dev))
pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
- pci_flr_wait(dev);
+ return pci_flr_wait(dev);
}
EXPORT_SYMBOL_GPL(pcie_flr);
@@ -4056,8 +4058,7 @@ static int pci_af_flr(struct pci_dev *de
pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
- pci_flr_wait(dev);
- return 0;
+ return pci_flr_wait(dev);
}
/**
@@ -4329,8 +4330,9 @@ int __pci_reset_function_locked(struct p
if (rc != -ENOTTY)
return rc;
if (pcie_has_flr(dev)) {
- pcie_flr(dev);
- return 0;
+ rc = pcie_flr(dev);
+ if (rc != -ENOTTY)
+ return rc;
}
rc = pci_af_flr(dev, 0);
if (rc != -ENOTTY)
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1089,7 +1089,7 @@ u32 pcie_bandwidth_available(struct pci_
enum pci_bus_speed *speed,
enum pcie_link_width *width);
void pcie_print_link_status(struct pci_dev *dev);
-void pcie_flr(struct pci_dev *dev);
+int pcie_flr(struct pci_dev *dev);
int __pci_reset_function(struct pci_dev *dev);
int __pci_reset_function_locked(struct pci_dev *dev);
int pci_reset_function(struct pci_dev *dev);