xref: /openbmc/linux/drivers/remoteproc/remoteproc_sysfs.c (revision 4a4dca1941fedc1b02635ff0b4ed51b9857d0382)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22aefbef0SMatt Redfearn /*
32aefbef0SMatt Redfearn  * Remote Processor Framework
42aefbef0SMatt Redfearn  */
52aefbef0SMatt Redfearn 
62aefbef0SMatt Redfearn #include <linux/remoteproc.h>
7bf89a7c0SMichael S. Tsirkin #include <linux/slab.h>
82aefbef0SMatt Redfearn 
92aefbef0SMatt Redfearn #include "remoteproc_internal.h"
102aefbef0SMatt Redfearn 
112aefbef0SMatt Redfearn #define to_rproc(d) container_of(d, struct rproc, dev)
122aefbef0SMatt Redfearn 
132aefbef0SMatt Redfearn /* Expose the loaded / running firmware name via sysfs */
142aefbef0SMatt Redfearn static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
152aefbef0SMatt Redfearn 			  char *buf)
162aefbef0SMatt Redfearn {
172aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
18*4a4dca19SMathieu Poirier 	const char *firmware = rproc->firmware;
192aefbef0SMatt Redfearn 
20*4a4dca19SMathieu Poirier 	/*
21*4a4dca19SMathieu Poirier 	 * If the remote processor has been started by an external
22*4a4dca19SMathieu Poirier 	 * entity we have no idea of what image it is running.  As such
23*4a4dca19SMathieu Poirier 	 * simply display a generic string rather then rproc->firmware.
24*4a4dca19SMathieu Poirier 	 *
25*4a4dca19SMathieu Poirier 	 * Here we rely on the autonomous flag because a remote processor
26*4a4dca19SMathieu Poirier 	 * may have been attached to and currently in a running state.
27*4a4dca19SMathieu Poirier 	 */
28*4a4dca19SMathieu Poirier 	if (rproc->autonomous)
29*4a4dca19SMathieu Poirier 		firmware = "unknown";
30*4a4dca19SMathieu Poirier 
31*4a4dca19SMathieu Poirier 	return sprintf(buf, "%s\n", firmware);
322aefbef0SMatt Redfearn }
332aefbef0SMatt Redfearn 
342aefbef0SMatt Redfearn /* Change firmware name via sysfs */
352aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev,
362aefbef0SMatt Redfearn 			      struct device_attribute *attr,
372aefbef0SMatt Redfearn 			      const char *buf, size_t count)
382aefbef0SMatt Redfearn {
392aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
402aefbef0SMatt Redfearn 	char *p;
412aefbef0SMatt Redfearn 	int err, len = count;
422aefbef0SMatt Redfearn 
432aefbef0SMatt Redfearn 	err = mutex_lock_interruptible(&rproc->lock);
442aefbef0SMatt Redfearn 	if (err) {
452aefbef0SMatt Redfearn 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
462aefbef0SMatt Redfearn 		return -EINVAL;
472aefbef0SMatt Redfearn 	}
482aefbef0SMatt Redfearn 
492aefbef0SMatt Redfearn 	if (rproc->state != RPROC_OFFLINE) {
502aefbef0SMatt Redfearn 		dev_err(dev, "can't change firmware while running\n");
512aefbef0SMatt Redfearn 		err = -EBUSY;
522aefbef0SMatt Redfearn 		goto out;
532aefbef0SMatt Redfearn 	}
542aefbef0SMatt Redfearn 
552aefbef0SMatt Redfearn 	len = strcspn(buf, "\n");
56faeadbb6SSuman Anna 	if (!len) {
57faeadbb6SSuman Anna 		dev_err(dev, "can't provide a NULL firmware\n");
58faeadbb6SSuman Anna 		err = -EINVAL;
59faeadbb6SSuman Anna 		goto out;
60faeadbb6SSuman Anna 	}
612aefbef0SMatt Redfearn 
622aefbef0SMatt Redfearn 	p = kstrndup(buf, len, GFP_KERNEL);
632aefbef0SMatt Redfearn 	if (!p) {
642aefbef0SMatt Redfearn 		err = -ENOMEM;
652aefbef0SMatt Redfearn 		goto out;
662aefbef0SMatt Redfearn 	}
672aefbef0SMatt Redfearn 
682aefbef0SMatt Redfearn 	kfree(rproc->firmware);
692aefbef0SMatt Redfearn 	rproc->firmware = p;
702aefbef0SMatt Redfearn out:
712aefbef0SMatt Redfearn 	mutex_unlock(&rproc->lock);
722aefbef0SMatt Redfearn 
732aefbef0SMatt Redfearn 	return err ? err : count;
742aefbef0SMatt Redfearn }
752aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware);
762aefbef0SMatt Redfearn 
772aefbef0SMatt Redfearn /*
782aefbef0SMatt Redfearn  * A state-to-string lookup table, for exposing a human readable state
792aefbef0SMatt Redfearn  * via sysfs. Always keep in sync with enum rproc_state
802aefbef0SMatt Redfearn  */
812aefbef0SMatt Redfearn static const char * const rproc_state_string[] = {
822aefbef0SMatt Redfearn 	[RPROC_OFFLINE]		= "offline",
832aefbef0SMatt Redfearn 	[RPROC_SUSPENDED]	= "suspended",
842aefbef0SMatt Redfearn 	[RPROC_RUNNING]		= "running",
852aefbef0SMatt Redfearn 	[RPROC_CRASHED]		= "crashed",
86608d7921SSarangdhar Joshi 	[RPROC_DELETED]		= "deleted",
87e2e5c55eSMathieu Poirier 	[RPROC_DETACHED]	= "detached",
882aefbef0SMatt Redfearn 	[RPROC_LAST]		= "invalid",
892aefbef0SMatt Redfearn };
902aefbef0SMatt Redfearn 
912aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */
922aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr,
932aefbef0SMatt Redfearn 			  char *buf)
942aefbef0SMatt Redfearn {
952aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
962aefbef0SMatt Redfearn 	unsigned int state;
972aefbef0SMatt Redfearn 
982aefbef0SMatt Redfearn 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
992aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc_state_string[state]);
1002aefbef0SMatt Redfearn }
1012aefbef0SMatt Redfearn 
1022aefbef0SMatt Redfearn /* Change remote processor state via sysfs */
1032aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev,
1042aefbef0SMatt Redfearn 			      struct device_attribute *attr,
1052aefbef0SMatt Redfearn 			      const char *buf, size_t count)
1062aefbef0SMatt Redfearn {
1072aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
1082aefbef0SMatt Redfearn 	int ret = 0;
1092aefbef0SMatt Redfearn 
1102aefbef0SMatt Redfearn 	if (sysfs_streq(buf, "start")) {
1112aefbef0SMatt Redfearn 		if (rproc->state == RPROC_RUNNING)
1122aefbef0SMatt Redfearn 			return -EBUSY;
1132aefbef0SMatt Redfearn 
1142aefbef0SMatt Redfearn 		ret = rproc_boot(rproc);
1152aefbef0SMatt Redfearn 		if (ret)
1162aefbef0SMatt Redfearn 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
1172aefbef0SMatt Redfearn 	} else if (sysfs_streq(buf, "stop")) {
1182aefbef0SMatt Redfearn 		if (rproc->state != RPROC_RUNNING)
1192aefbef0SMatt Redfearn 			return -EINVAL;
1202aefbef0SMatt Redfearn 
1212aefbef0SMatt Redfearn 		rproc_shutdown(rproc);
1222aefbef0SMatt Redfearn 	} else {
1232aefbef0SMatt Redfearn 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
1242aefbef0SMatt Redfearn 		ret = -EINVAL;
1252aefbef0SMatt Redfearn 	}
1262aefbef0SMatt Redfearn 	return ret ? ret : count;
1272aefbef0SMatt Redfearn }
1282aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state);
1292aefbef0SMatt Redfearn 
1306ed756aaSSuman Anna /* Expose the name of the remote processor via sysfs */
1316ed756aaSSuman Anna static ssize_t name_show(struct device *dev, struct device_attribute *attr,
1326ed756aaSSuman Anna 			 char *buf)
1336ed756aaSSuman Anna {
1346ed756aaSSuman Anna 	struct rproc *rproc = to_rproc(dev);
1356ed756aaSSuman Anna 
1366ed756aaSSuman Anna 	return sprintf(buf, "%s\n", rproc->name);
1376ed756aaSSuman Anna }
1386ed756aaSSuman Anna static DEVICE_ATTR_RO(name);
1396ed756aaSSuman Anna 
1402aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = {
1412aefbef0SMatt Redfearn 	&dev_attr_firmware.attr,
1422aefbef0SMatt Redfearn 	&dev_attr_state.attr,
1436ed756aaSSuman Anna 	&dev_attr_name.attr,
1442aefbef0SMatt Redfearn 	NULL
1452aefbef0SMatt Redfearn };
1462aefbef0SMatt Redfearn 
1472aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = {
1482aefbef0SMatt Redfearn 	.attrs = rproc_attrs
1492aefbef0SMatt Redfearn };
1502aefbef0SMatt Redfearn 
1512aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = {
1522aefbef0SMatt Redfearn 	&rproc_devgroup,
1532aefbef0SMatt Redfearn 	NULL
1542aefbef0SMatt Redfearn };
1552aefbef0SMatt Redfearn 
1562aefbef0SMatt Redfearn struct class rproc_class = {
1572aefbef0SMatt Redfearn 	.name		= "remoteproc",
1582aefbef0SMatt Redfearn 	.dev_groups	= rproc_devgroups,
1592aefbef0SMatt Redfearn };
1602aefbef0SMatt Redfearn 
1612aefbef0SMatt Redfearn int __init rproc_init_sysfs(void)
1622aefbef0SMatt Redfearn {
1632aefbef0SMatt Redfearn 	/* create remoteproc device class for sysfs */
1642aefbef0SMatt Redfearn 	int err = class_register(&rproc_class);
1652aefbef0SMatt Redfearn 
1662aefbef0SMatt Redfearn 	if (err)
1672aefbef0SMatt Redfearn 		pr_err("remoteproc: unable to register class\n");
1682aefbef0SMatt Redfearn 	return err;
1692aefbef0SMatt Redfearn }
1702aefbef0SMatt Redfearn 
1712aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void)
1722aefbef0SMatt Redfearn {
1732aefbef0SMatt Redfearn 	class_unregister(&rproc_class);
1742aefbef0SMatt Redfearn }
175