aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/cxl/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/cxl/pci.c')
-rw-r--r--drivers/misc/cxl/pci.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index a4a4e0217eed..428ea8ba25fc 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -21,6 +21,7 @@
#include <asm/msi_bitmap.h>
#include <asm/pci-bridge.h> /* for struct pci_controller */
#include <asm/pnv-pci.h>
+#include <asm/io.h>
#include "cxl.h"
@@ -741,6 +742,42 @@ static void cxl_remove_afu(struct cxl_afu *afu)
device_unregister(&afu->dev);
}
+int cxl_reset(struct cxl *adapter)
+{
+ struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+ int rc;
+ int i;
+ u32 val;
+
+ dev_info(&dev->dev, "CXL reset\n");
+
+ for (i = 0; i < adapter->slices; i++)
+ cxl_remove_afu(adapter->afu[i]);
+
+ /* pcie_warm_reset requests a fundamental pci reset which includes a
+ * PERST assert/deassert. PERST triggers a loading of the image
+ * if "user" or "factory" is selected in sysfs */
+ if ((rc = pci_set_pcie_reset_state(dev, pcie_warm_reset))) {
+ dev_err(&dev->dev, "cxl: pcie_warm_reset failed\n");
+ return rc;
+ }
+
+ /* the PERST done above fences the PHB. So, reset depends on EEH
+ * to unbind the driver, tell Sapphire to reinit the PHB, and rebind
+ * the driver. Do an mmio read explictly to ensure EEH notices the
+ * fenced PHB. Retry for a few seconds before giving up. */
+ i = 0;
+ while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) &&
+ (i < 5)) {
+ msleep(500);
+ i++;
+ }
+
+ if (val != 0xffffffff)
+ dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n");
+
+ return rc;
+}
static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
{