xref: /openbmc/linux/drivers/remoteproc/remoteproc_sysfs.c (revision 608d792192d7136d354bc1b44585c441164dc54e)
12aefbef0SMatt Redfearn /*
22aefbef0SMatt Redfearn  * Remote Processor Framework
32aefbef0SMatt Redfearn  *
42aefbef0SMatt Redfearn  * This program is free software; you can redistribute it and/or
52aefbef0SMatt Redfearn  * modify it under the terms of the GNU General Public License
62aefbef0SMatt Redfearn  * version 2 as published by the Free Software Foundation.
72aefbef0SMatt Redfearn  *
82aefbef0SMatt Redfearn  * This program is distributed in the hope that it will be useful,
92aefbef0SMatt Redfearn  * but WITHOUT ANY WARRANTY; without even the implied warranty of
102aefbef0SMatt Redfearn  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
112aefbef0SMatt Redfearn  * GNU General Public License for more details.
122aefbef0SMatt Redfearn  */
132aefbef0SMatt Redfearn 
142aefbef0SMatt Redfearn #include <linux/remoteproc.h>
152aefbef0SMatt Redfearn 
162aefbef0SMatt Redfearn #include "remoteproc_internal.h"
172aefbef0SMatt Redfearn 
182aefbef0SMatt Redfearn #define to_rproc(d) container_of(d, struct rproc, dev)
192aefbef0SMatt Redfearn 
202aefbef0SMatt Redfearn /* Expose the loaded / running firmware name via sysfs */
212aefbef0SMatt Redfearn static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
222aefbef0SMatt Redfearn 			  char *buf)
232aefbef0SMatt Redfearn {
242aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
252aefbef0SMatt Redfearn 
262aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc->firmware);
272aefbef0SMatt Redfearn }
282aefbef0SMatt Redfearn 
292aefbef0SMatt Redfearn /* Change firmware name via sysfs */
302aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev,
312aefbef0SMatt Redfearn 			      struct device_attribute *attr,
322aefbef0SMatt Redfearn 			      const char *buf, size_t count)
332aefbef0SMatt Redfearn {
342aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
352aefbef0SMatt Redfearn 	char *p;
362aefbef0SMatt Redfearn 	int err, len = count;
372aefbef0SMatt Redfearn 
382aefbef0SMatt Redfearn 	err = mutex_lock_interruptible(&rproc->lock);
392aefbef0SMatt Redfearn 	if (err) {
402aefbef0SMatt Redfearn 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
412aefbef0SMatt Redfearn 		return -EINVAL;
422aefbef0SMatt Redfearn 	}
432aefbef0SMatt Redfearn 
442aefbef0SMatt Redfearn 	if (rproc->state != RPROC_OFFLINE) {
452aefbef0SMatt Redfearn 		dev_err(dev, "can't change firmware while running\n");
462aefbef0SMatt Redfearn 		err = -EBUSY;
472aefbef0SMatt Redfearn 		goto out;
482aefbef0SMatt Redfearn 	}
492aefbef0SMatt Redfearn 
502aefbef0SMatt Redfearn 	len = strcspn(buf, "\n");
512aefbef0SMatt Redfearn 
522aefbef0SMatt Redfearn 	p = kstrndup(buf, len, GFP_KERNEL);
532aefbef0SMatt Redfearn 	if (!p) {
542aefbef0SMatt Redfearn 		err = -ENOMEM;
552aefbef0SMatt Redfearn 		goto out;
562aefbef0SMatt Redfearn 	}
572aefbef0SMatt Redfearn 
582aefbef0SMatt Redfearn 	kfree(rproc->firmware);
592aefbef0SMatt Redfearn 	rproc->firmware = p;
602aefbef0SMatt Redfearn out:
612aefbef0SMatt Redfearn 	mutex_unlock(&rproc->lock);
622aefbef0SMatt Redfearn 
632aefbef0SMatt Redfearn 	return err ? err : count;
642aefbef0SMatt Redfearn }
652aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware);
662aefbef0SMatt Redfearn 
672aefbef0SMatt Redfearn /*
682aefbef0SMatt Redfearn  * A state-to-string lookup table, for exposing a human readable state
692aefbef0SMatt Redfearn  * via sysfs. Always keep in sync with enum rproc_state
702aefbef0SMatt Redfearn  */
712aefbef0SMatt Redfearn static const char * const rproc_state_string[] = {
722aefbef0SMatt Redfearn 	[RPROC_OFFLINE]		= "offline",
732aefbef0SMatt Redfearn 	[RPROC_SUSPENDED]	= "suspended",
742aefbef0SMatt Redfearn 	[RPROC_RUNNING]		= "running",
752aefbef0SMatt Redfearn 	[RPROC_CRASHED]		= "crashed",
76*608d7921SSarangdhar Joshi 	[RPROC_DELETED]		= "deleted",
772aefbef0SMatt Redfearn 	[RPROC_LAST]		= "invalid",
782aefbef0SMatt Redfearn };
792aefbef0SMatt Redfearn 
802aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */
812aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr,
822aefbef0SMatt Redfearn 			  char *buf)
832aefbef0SMatt Redfearn {
842aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
852aefbef0SMatt Redfearn 	unsigned int state;
862aefbef0SMatt Redfearn 
872aefbef0SMatt Redfearn 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
882aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc_state_string[state]);
892aefbef0SMatt Redfearn }
902aefbef0SMatt Redfearn 
912aefbef0SMatt Redfearn /* Change remote processor state via sysfs */
922aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev,
932aefbef0SMatt Redfearn 			      struct device_attribute *attr,
942aefbef0SMatt Redfearn 			      const char *buf, size_t count)
952aefbef0SMatt Redfearn {
962aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
972aefbef0SMatt Redfearn 	int ret = 0;
982aefbef0SMatt Redfearn 
992aefbef0SMatt Redfearn 	if (sysfs_streq(buf, "start")) {
1002aefbef0SMatt Redfearn 		if (rproc->state == RPROC_RUNNING)
1012aefbef0SMatt Redfearn 			return -EBUSY;
1022aefbef0SMatt Redfearn 
1032aefbef0SMatt Redfearn 		ret = rproc_boot(rproc);
1042aefbef0SMatt Redfearn 		if (ret)
1052aefbef0SMatt Redfearn 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
1062aefbef0SMatt Redfearn 	} else if (sysfs_streq(buf, "stop")) {
1072aefbef0SMatt Redfearn 		if (rproc->state != RPROC_RUNNING)
1082aefbef0SMatt Redfearn 			return -EINVAL;
1092aefbef0SMatt Redfearn 
1102aefbef0SMatt Redfearn 		rproc_shutdown(rproc);
1112aefbef0SMatt Redfearn 	} else {
1122aefbef0SMatt Redfearn 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
1132aefbef0SMatt Redfearn 		ret = -EINVAL;
1142aefbef0SMatt Redfearn 	}
1152aefbef0SMatt Redfearn 	return ret ? ret : count;
1162aefbef0SMatt Redfearn }
1172aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state);
1182aefbef0SMatt Redfearn 
1192aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = {
1202aefbef0SMatt Redfearn 	&dev_attr_firmware.attr,
1212aefbef0SMatt Redfearn 	&dev_attr_state.attr,
1222aefbef0SMatt Redfearn 	NULL
1232aefbef0SMatt Redfearn };
1242aefbef0SMatt Redfearn 
1252aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = {
1262aefbef0SMatt Redfearn 	.attrs = rproc_attrs
1272aefbef0SMatt Redfearn };
1282aefbef0SMatt Redfearn 
1292aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = {
1302aefbef0SMatt Redfearn 	&rproc_devgroup,
1312aefbef0SMatt Redfearn 	NULL
1322aefbef0SMatt Redfearn };
1332aefbef0SMatt Redfearn 
1342aefbef0SMatt Redfearn struct class rproc_class = {
1352aefbef0SMatt Redfearn 	.name		= "remoteproc",
1362aefbef0SMatt Redfearn 	.dev_groups	= rproc_devgroups,
1372aefbef0SMatt Redfearn };
1382aefbef0SMatt Redfearn 
1392aefbef0SMatt Redfearn int __init rproc_init_sysfs(void)
1402aefbef0SMatt Redfearn {
1412aefbef0SMatt Redfearn 	/* create remoteproc device class for sysfs */
1422aefbef0SMatt Redfearn 	int err = class_register(&rproc_class);
1432aefbef0SMatt Redfearn 
1442aefbef0SMatt Redfearn 	if (err)
1452aefbef0SMatt Redfearn 		pr_err("remoteproc: unable to register class\n");
1462aefbef0SMatt Redfearn 	return err;
1472aefbef0SMatt Redfearn }
1482aefbef0SMatt Redfearn 
1492aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void)
1502aefbef0SMatt Redfearn {
1512aefbef0SMatt Redfearn 	class_unregister(&rproc_class);
1522aefbef0SMatt Redfearn }
153