[PATCH 1/3] CXL: Add image control to sysfs
Ryan Grimm
grimm at linux.vnet.ibm.com
Thu Jan 15 13:56:39 AEDT 2015
Add reset_loads_image and reset_image_select to sysfs.
reset_image_select identifies which image will be loaded to the card on the
next PERST. Valid entries are: "user" and "factory".
reset_loads_image defines functionality on a PERST. Value of 0 means PERST
will not cause image load. A power cycle is required to load the image. Value
of 1 means PERST will cause image load.
sysfs updates the cxl struct in the driver then calls cxl_update_image_control
to write the vals in the VSEC.
Signed-off-by: Ryan Grimm <grimm at linux.vnet.ibm.com>
---
Documentation/ABI/testing/sysfs-class-cxl | 15 ++++++++
drivers/misc/cxl/cxl.h | 1 +
drivers/misc/cxl/pci.c | 35 ++++++++++++++++++
drivers/misc/cxl/sysfs.c | 60 +++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl
index 554405e..134cfaf 100644
--- a/Documentation/ABI/testing/sysfs-class-cxl
+++ b/Documentation/ABI/testing/sysfs-class-cxl
@@ -127,3 +127,18 @@ Contact: linuxppc-dev at lists.ozlabs.org
Description: read only
Will return "user" or "factory" depending on the image loaded
onto the card.
+
+What: /sys/class/cxl/<card>/reset_image_select
+Date: December 2014
+Contact: linuxppc-dev at lists.ozlabs.org
+Description: read/write
+ Identifies which image will be loaded to the card on the next
+ PERST. Valid entries are: "user" and "factory".
+
+What: /sys/class/cxl/<card>/reset_loads_image
+Date: December 2014
+Contact: linuxppc-dev at lists.ozlabs.org
+Description: read/write
+ Value of 0 means PERST will not cause image load. A power
+ cycle is required to load the image. Value of 1 means PERST
+ will cause image load.
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index 0df0438..518c4c6 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -488,6 +488,7 @@ void cxl_release_one_irq(struct cxl *adapter, int hwirq);
int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
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);
/* common == phyp + powernv */
struct cxl_process_element_common {
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index f801c28..26cacc1 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -362,6 +362,41 @@ int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq,
return pnv_cxl_ioda_msi_setup(dev, hwirq, virq);
}
+int cxl_update_image_control(struct cxl *adapter)
+{
+ struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+ int rc;
+ int vsec;
+ u8 image_state;
+
+ if (!(vsec = find_cxl_vsec(dev))) {
+ dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
+ return -ENODEV;
+ }
+
+ if ((rc = CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state))) {
+ dev_err(&dev->dev, "failed to read image state: %i\n", rc);
+ return rc;
+ }
+
+ if (adapter->perst_loads_image)
+ image_state |= CXL_VSEC_PERST_LOADS_IMAGE;
+ else
+ image_state &= ~CXL_VSEC_PERST_LOADS_IMAGE;
+
+ if (adapter->perst_select_user)
+ image_state |= CXL_VSEC_PERST_SELECT_USER;
+ else
+ image_state &= ~CXL_VSEC_PERST_SELECT_USER;
+
+ if ((rc = CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, image_state))) {
+ dev_err(&dev->dev, "failed to update image control: %i\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
int cxl_alloc_one_irq(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
index 461bdbd..06f554b 100644
--- a/drivers/misc/cxl/sysfs.c
+++ b/drivers/misc/cxl/sysfs.c
@@ -56,11 +56,71 @@ static ssize_t image_loaded_show(struct device *device,
return scnprintf(buf, PAGE_SIZE, "factory\n");
}
+static ssize_t reset_loads_image_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+ return sprintf(buf, "%d\n", adapter->perst_loads_image);
+}
+
+static ssize_t reset_loads_image_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+ unsigned long val;
+ int rc;
+
+ if (kstrtoul(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ adapter->perst_loads_image = !!val;
+ if ((rc = cxl_update_image_control(adapter)))
+ return rc;
+
+ return count;
+}
+
+static ssize_t reset_image_select_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+
+ if (adapter->perst_select_user)
+ return scnprintf(buf, PAGE_SIZE, "user\n");
+
+ return scnprintf(buf, PAGE_SIZE, "factory\n");
+}
+
+static ssize_t reset_image_select_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+ int rc;
+
+ if (!strncmp(buf, "user", 4))
+ adapter->perst_select_user = true;
+ else if (!strncmp(buf, "factory", 7))
+ adapter->perst_select_user = false;
+ else
+ return -EINVAL;
+
+ if ((rc = cxl_update_image_control(adapter)))
+ return rc;
+
+ return count;
+}
+
static struct device_attribute adapter_attrs[] = {
__ATTR_RO(caia_version),
__ATTR_RO(psl_revision),
__ATTR_RO(base_image),
__ATTR_RO(image_loaded),
+ __ATTR_RW(reset_loads_image),
+ __ATTR_RW(reset_image_select),
};
--
1.9.1
More information about the Linuxppc-dev
mailing list