xref: /openbmc/linux/drivers/remoteproc/remoteproc_sysfs.c (revision 1802d0beecafe581ad584634ba92f8a471d8a63a)
1*1802d0beSThomas 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>
72aefbef0SMatt Redfearn 
82aefbef0SMatt Redfearn #include "remoteproc_internal.h"
92aefbef0SMatt Redfearn 
102aefbef0SMatt Redfearn #define to_rproc(d) container_of(d, struct rproc, dev)
112aefbef0SMatt Redfearn 
122aefbef0SMatt Redfearn /* Expose the loaded / running firmware name via sysfs */
132aefbef0SMatt Redfearn static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
142aefbef0SMatt Redfearn 			  char *buf)
152aefbef0SMatt Redfearn {
162aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
172aefbef0SMatt Redfearn 
182aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc->firmware);
192aefbef0SMatt Redfearn }
202aefbef0SMatt Redfearn 
212aefbef0SMatt Redfearn /* Change firmware name via sysfs */
222aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev,
232aefbef0SMatt Redfearn 			      struct device_attribute *attr,
242aefbef0SMatt Redfearn 			      const char *buf, size_t count)
252aefbef0SMatt Redfearn {
262aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
272aefbef0SMatt Redfearn 	char *p;
282aefbef0SMatt Redfearn 	int err, len = count;
292aefbef0SMatt Redfearn 
302aefbef0SMatt Redfearn 	err = mutex_lock_interruptible(&rproc->lock);
312aefbef0SMatt Redfearn 	if (err) {
322aefbef0SMatt Redfearn 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
332aefbef0SMatt Redfearn 		return -EINVAL;
342aefbef0SMatt Redfearn 	}
352aefbef0SMatt Redfearn 
362aefbef0SMatt Redfearn 	if (rproc->state != RPROC_OFFLINE) {
372aefbef0SMatt Redfearn 		dev_err(dev, "can't change firmware while running\n");
382aefbef0SMatt Redfearn 		err = -EBUSY;
392aefbef0SMatt Redfearn 		goto out;
402aefbef0SMatt Redfearn 	}
412aefbef0SMatt Redfearn 
422aefbef0SMatt Redfearn 	len = strcspn(buf, "\n");
43faeadbb6SSuman Anna 	if (!len) {
44faeadbb6SSuman Anna 		dev_err(dev, "can't provide a NULL firmware\n");
45faeadbb6SSuman Anna 		err = -EINVAL;
46faeadbb6SSuman Anna 		goto out;
47faeadbb6SSuman Anna 	}
482aefbef0SMatt Redfearn 
492aefbef0SMatt Redfearn 	p = kstrndup(buf, len, GFP_KERNEL);
502aefbef0SMatt Redfearn 	if (!p) {
512aefbef0SMatt Redfearn 		err = -ENOMEM;
522aefbef0SMatt Redfearn 		goto out;
532aefbef0SMatt Redfearn 	}
542aefbef0SMatt Redfearn 
552aefbef0SMatt Redfearn 	kfree(rproc->firmware);
562aefbef0SMatt Redfearn 	rproc->firmware = p;
572aefbef0SMatt Redfearn out:
582aefbef0SMatt Redfearn 	mutex_unlock(&rproc->lock);
592aefbef0SMatt Redfearn 
602aefbef0SMatt Redfearn 	return err ? err : count;
612aefbef0SMatt Redfearn }
622aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware);
632aefbef0SMatt Redfearn 
642aefbef0SMatt Redfearn /*
652aefbef0SMatt Redfearn  * A state-to-string lookup table, for exposing a human readable state
662aefbef0SMatt Redfearn  * via sysfs. Always keep in sync with enum rproc_state
672aefbef0SMatt Redfearn  */
682aefbef0SMatt Redfearn static const char * const rproc_state_string[] = {
692aefbef0SMatt Redfearn 	[RPROC_OFFLINE]		= "offline",
702aefbef0SMatt Redfearn 	[RPROC_SUSPENDED]	= "suspended",
712aefbef0SMatt Redfearn 	[RPROC_RUNNING]		= "running",
722aefbef0SMatt Redfearn 	[RPROC_CRASHED]		= "crashed",
73608d7921SSarangdhar Joshi 	[RPROC_DELETED]		= "deleted",
742aefbef0SMatt Redfearn 	[RPROC_LAST]		= "invalid",
752aefbef0SMatt Redfearn };
762aefbef0SMatt Redfearn 
772aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */
782aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr,
792aefbef0SMatt Redfearn 			  char *buf)
802aefbef0SMatt Redfearn {
812aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
822aefbef0SMatt Redfearn 	unsigned int state;
832aefbef0SMatt Redfearn 
842aefbef0SMatt Redfearn 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
852aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc_state_string[state]);
862aefbef0SMatt Redfearn }
872aefbef0SMatt Redfearn 
882aefbef0SMatt Redfearn /* Change remote processor state via sysfs */
892aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev,
902aefbef0SMatt Redfearn 			      struct device_attribute *attr,
912aefbef0SMatt Redfearn 			      const char *buf, size_t count)
922aefbef0SMatt Redfearn {
932aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
942aefbef0SMatt Redfearn 	int ret = 0;
952aefbef0SMatt Redfearn 
962aefbef0SMatt Redfearn 	if (sysfs_streq(buf, "start")) {
972aefbef0SMatt Redfearn 		if (rproc->state == RPROC_RUNNING)
982aefbef0SMatt Redfearn 			return -EBUSY;
992aefbef0SMatt Redfearn 
1002aefbef0SMatt Redfearn 		ret = rproc_boot(rproc);
1012aefbef0SMatt Redfearn 		if (ret)
1022aefbef0SMatt Redfearn 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
1032aefbef0SMatt Redfearn 	} else if (sysfs_streq(buf, "stop")) {
1042aefbef0SMatt Redfearn 		if (rproc->state != RPROC_RUNNING)
1052aefbef0SMatt Redfearn 			return -EINVAL;
1062aefbef0SMatt Redfearn 
1072aefbef0SMatt Redfearn 		rproc_shutdown(rproc);
1082aefbef0SMatt Redfearn 	} else {
1092aefbef0SMatt Redfearn 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
1102aefbef0SMatt Redfearn 		ret = -EINVAL;
1112aefbef0SMatt Redfearn 	}
1122aefbef0SMatt Redfearn 	return ret ? ret : count;
1132aefbef0SMatt Redfearn }
1142aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state);
1152aefbef0SMatt Redfearn 
1162aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = {
1172aefbef0SMatt Redfearn 	&dev_attr_firmware.attr,
1182aefbef0SMatt Redfearn 	&dev_attr_state.attr,
1192aefbef0SMatt Redfearn 	NULL
1202aefbef0SMatt Redfearn };
1212aefbef0SMatt Redfearn 
1222aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = {
1232aefbef0SMatt Redfearn 	.attrs = rproc_attrs
1242aefbef0SMatt Redfearn };
1252aefbef0SMatt Redfearn 
1262aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = {
1272aefbef0SMatt Redfearn 	&rproc_devgroup,
1282aefbef0SMatt Redfearn 	NULL
1292aefbef0SMatt Redfearn };
1302aefbef0SMatt Redfearn 
1312aefbef0SMatt Redfearn struct class rproc_class = {
1322aefbef0SMatt Redfearn 	.name		= "remoteproc",
1332aefbef0SMatt Redfearn 	.dev_groups	= rproc_devgroups,
1342aefbef0SMatt Redfearn };
1352aefbef0SMatt Redfearn 
1362aefbef0SMatt Redfearn int __init rproc_init_sysfs(void)
1372aefbef0SMatt Redfearn {
1382aefbef0SMatt Redfearn 	/* create remoteproc device class for sysfs */
1392aefbef0SMatt Redfearn 	int err = class_register(&rproc_class);
1402aefbef0SMatt Redfearn 
1412aefbef0SMatt Redfearn 	if (err)
1422aefbef0SMatt Redfearn 		pr_err("remoteproc: unable to register class\n");
1432aefbef0SMatt Redfearn 	return err;
1442aefbef0SMatt Redfearn }
1452aefbef0SMatt Redfearn 
1462aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void)
1472aefbef0SMatt Redfearn {
1482aefbef0SMatt Redfearn 	class_unregister(&rproc_class);
1492aefbef0SMatt Redfearn }
150