cxl: Add ability to reset the card
Adds reset to sysfs which will PERST the card. If load_image_on_perst is set to "user" or "factory", the PERST will cause that image to be loaded. load_image_on_perst is set to "user" for production. "none" could be used for debugging. The PSL trace arrays are preserved which then can be read through debugfs. PERST also triggers CAPP recovery. An HMI comes in, which is handled by EEH. EEH unbinds the driver, calls into Sapphire to reinitialize the PHB, then rebinds the driver. Signed-off-by: Ryan Grimm <grimm@linux.vnet.ibm.com> Acked-by: Ian Munsie <imunsie@au1.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Родитель
1212aa1c8c
Коммит
62fa19d4b4
|
@ -146,3 +146,10 @@ Description: read/write
|
||||||
user or factory image to be loaded.
|
user or factory image to be loaded.
|
||||||
Default is to reload on PERST whichever image the card has
|
Default is to reload on PERST whichever image the card has
|
||||||
loaded.
|
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.
|
||||||
|
|
|
@ -489,6 +489,7 @@ int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsig
|
||||||
void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
|
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_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
|
||||||
int cxl_update_image_control(struct cxl *adapter);
|
int cxl_update_image_control(struct cxl *adapter);
|
||||||
|
int cxl_reset(struct cxl *adapter);
|
||||||
|
|
||||||
/* common == phyp + powernv */
|
/* common == phyp + powernv */
|
||||||
struct cxl_process_element_common {
|
struct cxl_process_element_common {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <asm/msi_bitmap.h>
|
#include <asm/msi_bitmap.h>
|
||||||
#include <asm/pci-bridge.h> /* for struct pci_controller */
|
#include <asm/pci-bridge.h> /* for struct pci_controller */
|
||||||
#include <asm/pnv-pci.h>
|
#include <asm/pnv-pci.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
|
||||||
#include "cxl.h"
|
#include "cxl.h"
|
||||||
|
|
||||||
|
@ -741,6 +742,42 @@ static void cxl_remove_afu(struct cxl_afu *afu)
|
||||||
device_unregister(&afu->dev);
|
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)
|
static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,6 +56,23 @@ static ssize_t image_loaded_show(struct device *device,
|
||||||
return scnprintf(buf, PAGE_SIZE, "factory\n");
|
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,
|
static ssize_t load_image_on_perst_show(struct device *device,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
|
@ -100,6 +117,7 @@ static struct device_attribute adapter_attrs[] = {
|
||||||
__ATTR_RO(base_image),
|
__ATTR_RO(base_image),
|
||||||
__ATTR_RO(image_loaded),
|
__ATTR_RO(image_loaded),
|
||||||
__ATTR_RW(load_image_on_perst),
|
__ATTR_RW(load_image_on_perst),
|
||||||
|
__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче