diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-cxl | 7 | ||||
-rw-r--r-- | drivers/misc/cxl/cxl.h | 1 | ||||
-rw-r--r-- | drivers/misc/cxl/pci.c | 37 | ||||
-rw-r--r-- | drivers/misc/cxl/sysfs.c | 18 |
4 files changed, 63 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl index 5941ff38d4a3..9ea01068a16c 100644 --- a/Documentation/ABI/testing/sysfs-class-cxl +++ b/Documentation/ABI/testing/sysfs-class-cxl | |||
@@ -146,3 +146,10 @@ Description: read/write | |||
146 | user or factory image to be loaded. | 146 | user or factory image to be loaded. |
147 | Default is to reload on PERST whichever image the card has | 147 | Default is to reload on PERST whichever image the card has |
148 | loaded. | 148 | loaded. |
149 | |||
150 | What: /sys/class/cxl/<card>/reset | ||
151 | Date: October 2014 | ||
152 | Contact: linuxppc-dev@lists.ozlabs.org | ||
153 | Description: write only | ||
154 | Writing 1 will issue a PERST to card which may cause the card | ||
155 | to reload the FPGA depending on load_image_on_perst. | ||
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 518c4c6e6151..6a6a487464c5 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h | |||
@@ -489,6 +489,7 @@ int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsig | |||
489 | void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter); | 489 | void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter); |
490 | int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq); | 490 | int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq); |
491 | int cxl_update_image_control(struct cxl *adapter); | 491 | int cxl_update_image_control(struct cxl *adapter); |
492 | int cxl_reset(struct cxl *adapter); | ||
492 | 493 | ||
493 | /* common == phyp + powernv */ | 494 | /* common == phyp + powernv */ |
494 | struct cxl_process_element_common { | 495 | struct cxl_process_element_common { |
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 @@ | |||
21 | #include <asm/msi_bitmap.h> | 21 | #include <asm/msi_bitmap.h> |
22 | #include <asm/pci-bridge.h> /* for struct pci_controller */ | 22 | #include <asm/pci-bridge.h> /* for struct pci_controller */ |
23 | #include <asm/pnv-pci.h> | 23 | #include <asm/pnv-pci.h> |
24 | #include <asm/io.h> | ||
24 | 25 | ||
25 | #include "cxl.h" | 26 | #include "cxl.h" |
26 | 27 | ||
@@ -741,6 +742,42 @@ static void cxl_remove_afu(struct cxl_afu *afu) | |||
741 | device_unregister(&afu->dev); | 742 | device_unregister(&afu->dev); |
742 | } | 743 | } |
743 | 744 | ||
745 | int cxl_reset(struct cxl *adapter) | ||
746 | { | ||
747 | struct pci_dev *dev = to_pci_dev(adapter->dev.parent); | ||
748 | int rc; | ||
749 | int i; | ||
750 | u32 val; | ||
751 | |||
752 | dev_info(&dev->dev, "CXL reset\n"); | ||
753 | |||
754 | for (i = 0; i < adapter->slices; i++) | ||
755 | cxl_remove_afu(adapter->afu[i]); | ||
756 | |||
757 | /* pcie_warm_reset requests a fundamental pci reset which includes a | ||
758 | * PERST assert/deassert. PERST triggers a loading of the image | ||
759 | * if "user" or "factory" is selected in sysfs */ | ||
760 | if ((rc = pci_set_pcie_reset_state(dev, pcie_warm_reset))) { | ||
761 | dev_err(&dev->dev, "cxl: pcie_warm_reset failed\n"); | ||
762 | return rc; | ||
763 | } | ||
764 | |||
765 | /* the PERST done above fences the PHB. So, reset depends on EEH | ||
766 | * to unbind the driver, tell Sapphire to reinit the PHB, and rebind | ||
767 | * the driver. Do an mmio read explictly to ensure EEH notices the | ||
768 | * fenced PHB. Retry for a few seconds before giving up. */ | ||
769 | i = 0; | ||
770 | while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) && | ||
771 | (i < 5)) { | ||
772 | msleep(500); | ||
773 | i++; | ||
774 | } | ||
775 | |||
776 | if (val != 0xffffffff) | ||
777 | dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n"); | ||
778 | |||
779 | return rc; | ||
780 | } | ||
744 | 781 | ||
745 | static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) | 782 | static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) |
746 | { | 783 | { |
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index ed4ad461143c..adf1f6d84913 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c | |||
@@ -56,6 +56,23 @@ static ssize_t image_loaded_show(struct device *device, | |||
56 | return scnprintf(buf, PAGE_SIZE, "factory\n"); | 56 | return scnprintf(buf, PAGE_SIZE, "factory\n"); |
57 | } | 57 | } |
58 | 58 | ||
59 | static ssize_t reset_adapter_store(struct device *device, | ||
60 | struct device_attribute *attr, | ||
61 | const char *buf, size_t count) | ||
62 | { | ||
63 | struct cxl *adapter = to_cxl_adapter(device); | ||
64 | int rc; | ||
65 | int val; | ||
66 | |||
67 | rc = sscanf(buf, "%i", &val); | ||
68 | if ((rc != 1) || (val != 1)) | ||
69 | return -EINVAL; | ||
70 | |||
71 | if ((rc = cxl_reset(adapter))) | ||
72 | return rc; | ||
73 | return count; | ||
74 | } | ||
75 | |||
59 | static ssize_t load_image_on_perst_show(struct device *device, | 76 | static ssize_t load_image_on_perst_show(struct device *device, |
60 | struct device_attribute *attr, | 77 | struct device_attribute *attr, |
61 | char *buf) | 78 | char *buf) |
@@ -100,6 +117,7 @@ static struct device_attribute adapter_attrs[] = { | |||
100 | __ATTR_RO(base_image), | 117 | __ATTR_RO(base_image), |
101 | __ATTR_RO(image_loaded), | 118 | __ATTR_RO(image_loaded), |
102 | __ATTR_RW(load_image_on_perst), | 119 | __ATTR_RW(load_image_on_perst), |
120 | __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), | ||
103 | }; | 121 | }; |
104 | 122 | ||
105 | 123 | ||