xref: /openbmc/linux/drivers/remoteproc/remoteproc_sysfs.c (revision bf89a7c0218f5cbc0778b5a1b353006339a07421)
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>
7*bf89a7c0SMichael 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);
182aefbef0SMatt Redfearn 
192aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc->firmware);
202aefbef0SMatt Redfearn }
212aefbef0SMatt Redfearn 
222aefbef0SMatt Redfearn /* Change firmware name via sysfs */
232aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev,
242aefbef0SMatt Redfearn 			      struct device_attribute *attr,
252aefbef0SMatt Redfearn 			      const char *buf, size_t count)
262aefbef0SMatt Redfearn {
272aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
282aefbef0SMatt Redfearn 	char *p;
292aefbef0SMatt Redfearn 	int err, len = count;
302aefbef0SMatt Redfearn 
312aefbef0SMatt Redfearn 	err = mutex_lock_interruptible(&rproc->lock);
322aefbef0SMatt Redfearn 	if (err) {
332aefbef0SMatt Redfearn 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
342aefbef0SMatt Redfearn 		return -EINVAL;
352aefbef0SMatt Redfearn 	}
362aefbef0SMatt Redfearn 
372aefbef0SMatt Redfearn 	if (rproc->state != RPROC_OFFLINE) {
382aefbef0SMatt Redfearn 		dev_err(dev, "can't change firmware while running\n");
392aefbef0SMatt Redfearn 		err = -EBUSY;
402aefbef0SMatt Redfearn 		goto out;
412aefbef0SMatt Redfearn 	}
422aefbef0SMatt Redfearn 
432aefbef0SMatt Redfearn 	len = strcspn(buf, "\n");
44faeadbb6SSuman Anna 	if (!len) {
45faeadbb6SSuman Anna 		dev_err(dev, "can't provide a NULL firmware\n");
46faeadbb6SSuman Anna 		err = -EINVAL;
47faeadbb6SSuman Anna 		goto out;
48faeadbb6SSuman Anna 	}
492aefbef0SMatt Redfearn 
502aefbef0SMatt Redfearn 	p = kstrndup(buf, len, GFP_KERNEL);
512aefbef0SMatt Redfearn 	if (!p) {
522aefbef0SMatt Redfearn 		err = -ENOMEM;
532aefbef0SMatt Redfearn 		goto out;
542aefbef0SMatt Redfearn 	}
552aefbef0SMatt Redfearn 
562aefbef0SMatt Redfearn 	kfree(rproc->firmware);
572aefbef0SMatt Redfearn 	rproc->firmware = p;
582aefbef0SMatt Redfearn out:
592aefbef0SMatt Redfearn 	mutex_unlock(&rproc->lock);
602aefbef0SMatt Redfearn 
612aefbef0SMatt Redfearn 	return err ? err : count;
622aefbef0SMatt Redfearn }
632aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware);
642aefbef0SMatt Redfearn 
652aefbef0SMatt Redfearn /*
662aefbef0SMatt Redfearn  * A state-to-string lookup table, for exposing a human readable state
672aefbef0SMatt Redfearn  * via sysfs. Always keep in sync with enum rproc_state
682aefbef0SMatt Redfearn  */
692aefbef0SMatt Redfearn static const char * const rproc_state_string[] = {
702aefbef0SMatt Redfearn 	[RPROC_OFFLINE]		= "offline",
712aefbef0SMatt Redfearn 	[RPROC_SUSPENDED]	= "suspended",
722aefbef0SMatt Redfearn 	[RPROC_RUNNING]		= "running",
732aefbef0SMatt Redfearn 	[RPROC_CRASHED]		= "crashed",
74608d7921SSarangdhar Joshi 	[RPROC_DELETED]		= "deleted",
752aefbef0SMatt Redfearn 	[RPROC_LAST]		= "invalid",
762aefbef0SMatt Redfearn };
772aefbef0SMatt Redfearn 
782aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */
792aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr,
802aefbef0SMatt Redfearn 			  char *buf)
812aefbef0SMatt Redfearn {
822aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
832aefbef0SMatt Redfearn 	unsigned int state;
842aefbef0SMatt Redfearn 
852aefbef0SMatt Redfearn 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
862aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc_state_string[state]);
872aefbef0SMatt Redfearn }
882aefbef0SMatt Redfearn 
892aefbef0SMatt Redfearn /* Change remote processor state via sysfs */
902aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev,
912aefbef0SMatt Redfearn 			      struct device_attribute *attr,
922aefbef0SMatt Redfearn 			      const char *buf, size_t count)
932aefbef0SMatt Redfearn {
942aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
952aefbef0SMatt Redfearn 	int ret = 0;
962aefbef0SMatt Redfearn 
972aefbef0SMatt Redfearn 	if (sysfs_streq(buf, "start")) {
982aefbef0SMatt Redfearn 		if (rproc->state == RPROC_RUNNING)
992aefbef0SMatt Redfearn 			return -EBUSY;
1002aefbef0SMatt Redfearn 
1012aefbef0SMatt Redfearn 		ret = rproc_boot(rproc);
1022aefbef0SMatt Redfearn 		if (ret)
1032aefbef0SMatt Redfearn 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
1042aefbef0SMatt Redfearn 	} else if (sysfs_streq(buf, "stop")) {
1052aefbef0SMatt Redfearn 		if (rproc->state != RPROC_RUNNING)
1062aefbef0SMatt Redfearn 			return -EINVAL;
1072aefbef0SMatt Redfearn 
1082aefbef0SMatt Redfearn 		rproc_shutdown(rproc);
1092aefbef0SMatt Redfearn 	} else {
1102aefbef0SMatt Redfearn 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
1112aefbef0SMatt Redfearn 		ret = -EINVAL;
1122aefbef0SMatt Redfearn 	}
1132aefbef0SMatt Redfearn 	return ret ? ret : count;
1142aefbef0SMatt Redfearn }
1152aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state);
1162aefbef0SMatt Redfearn 
1176ed756aaSSuman Anna /* Expose the name of the remote processor via sysfs */
1186ed756aaSSuman Anna static ssize_t name_show(struct device *dev, struct device_attribute *attr,
1196ed756aaSSuman Anna 			 char *buf)
1206ed756aaSSuman Anna {
1216ed756aaSSuman Anna 	struct rproc *rproc = to_rproc(dev);
1226ed756aaSSuman Anna 
1236ed756aaSSuman Anna 	return sprintf(buf, "%s\n", rproc->name);
1246ed756aaSSuman Anna }
1256ed756aaSSuman Anna static DEVICE_ATTR_RO(name);
1266ed756aaSSuman Anna 
1272aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = {
1282aefbef0SMatt Redfearn 	&dev_attr_firmware.attr,
1292aefbef0SMatt Redfearn 	&dev_attr_state.attr,
1306ed756aaSSuman Anna 	&dev_attr_name.attr,
1312aefbef0SMatt Redfearn 	NULL
1322aefbef0SMatt Redfearn };
1332aefbef0SMatt Redfearn 
1342aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = {
1352aefbef0SMatt Redfearn 	.attrs = rproc_attrs
1362aefbef0SMatt Redfearn };
1372aefbef0SMatt Redfearn 
1382aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = {
1392aefbef0SMatt Redfearn 	&rproc_devgroup,
1402aefbef0SMatt Redfearn 	NULL
1412aefbef0SMatt Redfearn };
1422aefbef0SMatt Redfearn 
1432aefbef0SMatt Redfearn struct class rproc_class = {
1442aefbef0SMatt Redfearn 	.name		= "remoteproc",
1452aefbef0SMatt Redfearn 	.dev_groups	= rproc_devgroups,
1462aefbef0SMatt Redfearn };
1472aefbef0SMatt Redfearn 
1482aefbef0SMatt Redfearn int __init rproc_init_sysfs(void)
1492aefbef0SMatt Redfearn {
1502aefbef0SMatt Redfearn 	/* create remoteproc device class for sysfs */
1512aefbef0SMatt Redfearn 	int err = class_register(&rproc_class);
1522aefbef0SMatt Redfearn 
1532aefbef0SMatt Redfearn 	if (err)
1542aefbef0SMatt Redfearn 		pr_err("remoteproc: unable to register class\n");
1552aefbef0SMatt Redfearn 	return err;
1562aefbef0SMatt Redfearn }
1572aefbef0SMatt Redfearn 
1582aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void)
1592aefbef0SMatt Redfearn {
1602aefbef0SMatt Redfearn 	class_unregister(&rproc_class);
1612aefbef0SMatt Redfearn }
162