user or factory image to be loaded.
                 Default is to reload on PERST whichever image the card has
                 loaded.
+
+What:           /sys/class/cxl/<card>/reset
+Date:           October 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    write only
+                Writing 1 will issue a PERST to card which may cause the card
+                to reload the FPGA depending on load_image_on_perst.
 
 void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
 int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
 int cxl_update_image_control(struct cxl *adapter);
+int cxl_reset(struct cxl *adapter);
 
 /* common == phyp + powernv */
 struct cxl_process_element_common {
 
 #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"
 
        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)
 {
 
        return scnprintf(buf, PAGE_SIZE, "factory\n");
 }
 
+static ssize_t reset_adapter_store(struct device *device,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct cxl *adapter = to_cxl_adapter(device);
+       int rc;
+       int val;
+
+       rc = sscanf(buf, "%i", &val);
+       if ((rc != 1) || (val != 1))
+               return -EINVAL;
+
+       if ((rc = cxl_reset(adapter)))
+               return rc;
+       return count;
+}
+
 static ssize_t load_image_on_perst_show(struct device *device,
                                 struct device_attribute *attr,
                                 char *buf)
        __ATTR_RO(base_image),
        __ATTR_RO(image_loaded),
        __ATTR_RW(load_image_on_perst),
+       __ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
 };