1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Remote Processor Framework
4  */
5 
6 #include <linux/remoteproc.h>
7 #include <linux/slab.h>
8 
9 #include "remoteproc_internal.h"
10 
11 #define to_rproc(d) container_of(d, struct rproc, dev)
12 
13 /* Expose the loaded / running firmware name via sysfs */
14 static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
15 			  char *buf)
16 {
17 	struct rproc *rproc = to_rproc(dev);
18 	const char *firmware = rproc->firmware;
19 
20 	/*
21 	 * If the remote processor has been started by an external
22 	 * entity we have no idea of what image it is running.  As such
23 	 * simply display a generic string rather then rproc->firmware.
24 	 *
25 	 * Here we rely on the autonomous flag because a remote processor
26 	 * may have been attached to and currently in a running state.
27 	 */
28 	if (rproc->autonomous)
29 		firmware = "unknown";
30 
31 	return sprintf(buf, "%s\n", firmware);
32 }
33 
34 /* Change firmware name via sysfs */
35 static ssize_t firmware_store(struct device *dev,
36 			      struct device_attribute *attr,
37 			      const char *buf, size_t count)
38 {
39 	struct rproc *rproc = to_rproc(dev);
40 	char *p;
41 	int err, len = count;
42 
43 	err = mutex_lock_interruptible(&rproc->lock);
44 	if (err) {
45 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
46 		return -EINVAL;
47 	}
48 
49 	if (rproc->state != RPROC_OFFLINE) {
50 		dev_err(dev, "can't change firmware while running\n");
51 		err = -EBUSY;
52 		goto out;
53 	}
54 
55 	len = strcspn(buf, "\n");
56 	if (!len) {
57 		dev_err(dev, "can't provide a NULL firmware\n");
58 		err = -EINVAL;
59 		goto out;
60 	}
61 
62 	p = kstrndup(buf, len, GFP_KERNEL);
63 	if (!p) {
64 		err = -ENOMEM;
65 		goto out;
66 	}
67 
68 	kfree(rproc->firmware);
69 	rproc->firmware = p;
70 out:
71 	mutex_unlock(&rproc->lock);
72 
73 	return err ? err : count;
74 }
75 static DEVICE_ATTR_RW(firmware);
76 
77 /*
78  * A state-to-string lookup table, for exposing a human readable state
79  * via sysfs. Always keep in sync with enum rproc_state
80  */
81 static const char * const rproc_state_string[] = {
82 	[RPROC_OFFLINE]		= "offline",
83 	[RPROC_SUSPENDED]	= "suspended",
84 	[RPROC_RUNNING]		= "running",
85 	[RPROC_CRASHED]		= "crashed",
86 	[RPROC_DELETED]		= "deleted",
87 	[RPROC_DETACHED]	= "detached",
88 	[RPROC_LAST]		= "invalid",
89 };
90 
91 /* Expose the state of the remote processor via sysfs */
92 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
93 			  char *buf)
94 {
95 	struct rproc *rproc = to_rproc(dev);
96 	unsigned int state;
97 
98 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
99 	return sprintf(buf, "%s\n", rproc_state_string[state]);
100 }
101 
102 /* Change remote processor state via sysfs */
103 static ssize_t state_store(struct device *dev,
104 			      struct device_attribute *attr,
105 			      const char *buf, size_t count)
106 {
107 	struct rproc *rproc = to_rproc(dev);
108 	int ret = 0;
109 
110 	if (sysfs_streq(buf, "start")) {
111 		if (rproc->state == RPROC_RUNNING)
112 			return -EBUSY;
113 
114 		ret = rproc_boot(rproc);
115 		if (ret)
116 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
117 	} else if (sysfs_streq(buf, "stop")) {
118 		if (rproc->state != RPROC_RUNNING)
119 			return -EINVAL;
120 
121 		rproc_shutdown(rproc);
122 	} else {
123 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
124 		ret = -EINVAL;
125 	}
126 	return ret ? ret : count;
127 }
128 static DEVICE_ATTR_RW(state);
129 
130 /* Expose the name of the remote processor via sysfs */
131 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
132 			 char *buf)
133 {
134 	struct rproc *rproc = to_rproc(dev);
135 
136 	return sprintf(buf, "%s\n", rproc->name);
137 }
138 static DEVICE_ATTR_RO(name);
139 
140 static struct attribute *rproc_attrs[] = {
141 	&dev_attr_firmware.attr,
142 	&dev_attr_state.attr,
143 	&dev_attr_name.attr,
144 	NULL
145 };
146 
147 static const struct attribute_group rproc_devgroup = {
148 	.attrs = rproc_attrs
149 };
150 
151 static const struct attribute_group *rproc_devgroups[] = {
152 	&rproc_devgroup,
153 	NULL
154 };
155 
156 struct class rproc_class = {
157 	.name		= "remoteproc",
158 	.dev_groups	= rproc_devgroups,
159 };
160 
161 int __init rproc_init_sysfs(void)
162 {
163 	/* create remoteproc device class for sysfs */
164 	int err = class_register(&rproc_class);
165 
166 	if (err)
167 		pr_err("remoteproc: unable to register class\n");
168 	return err;
169 }
170 
171 void __exit rproc_exit_sysfs(void)
172 {
173 	class_unregister(&rproc_class);
174 }
175