xref: /openbmc/linux/drivers/remoteproc/remoteproc_sysfs.c (revision 2aefbef041498182ce1d186ed2300298b7a7101a)
1*2aefbef0SMatt Redfearn /*
2*2aefbef0SMatt Redfearn  * Remote Processor Framework
3*2aefbef0SMatt Redfearn  *
4*2aefbef0SMatt Redfearn  * This program is free software; you can redistribute it and/or
5*2aefbef0SMatt Redfearn  * modify it under the terms of the GNU General Public License
6*2aefbef0SMatt Redfearn  * version 2 as published by the Free Software Foundation.
7*2aefbef0SMatt Redfearn  *
8*2aefbef0SMatt Redfearn  * This program is distributed in the hope that it will be useful,
9*2aefbef0SMatt Redfearn  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10*2aefbef0SMatt Redfearn  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*2aefbef0SMatt Redfearn  * GNU General Public License for more details.
12*2aefbef0SMatt Redfearn  */
13*2aefbef0SMatt Redfearn 
14*2aefbef0SMatt Redfearn #include <linux/remoteproc.h>
15*2aefbef0SMatt Redfearn 
16*2aefbef0SMatt Redfearn #include "remoteproc_internal.h"
17*2aefbef0SMatt Redfearn 
18*2aefbef0SMatt Redfearn #define to_rproc(d) container_of(d, struct rproc, dev)
19*2aefbef0SMatt Redfearn 
20*2aefbef0SMatt Redfearn /* Expose the loaded / running firmware name via sysfs */
21*2aefbef0SMatt Redfearn static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
22*2aefbef0SMatt Redfearn 			  char *buf)
23*2aefbef0SMatt Redfearn {
24*2aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
25*2aefbef0SMatt Redfearn 
26*2aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc->firmware);
27*2aefbef0SMatt Redfearn }
28*2aefbef0SMatt Redfearn 
29*2aefbef0SMatt Redfearn /* Change firmware name via sysfs */
30*2aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev,
31*2aefbef0SMatt Redfearn 			      struct device_attribute *attr,
32*2aefbef0SMatt Redfearn 			      const char *buf, size_t count)
33*2aefbef0SMatt Redfearn {
34*2aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
35*2aefbef0SMatt Redfearn 	char *p;
36*2aefbef0SMatt Redfearn 	int err, len = count;
37*2aefbef0SMatt Redfearn 
38*2aefbef0SMatt Redfearn 	err = mutex_lock_interruptible(&rproc->lock);
39*2aefbef0SMatt Redfearn 	if (err) {
40*2aefbef0SMatt Redfearn 		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
41*2aefbef0SMatt Redfearn 		return -EINVAL;
42*2aefbef0SMatt Redfearn 	}
43*2aefbef0SMatt Redfearn 
44*2aefbef0SMatt Redfearn 	if (rproc->state != RPROC_OFFLINE) {
45*2aefbef0SMatt Redfearn 		dev_err(dev, "can't change firmware while running\n");
46*2aefbef0SMatt Redfearn 		err = -EBUSY;
47*2aefbef0SMatt Redfearn 		goto out;
48*2aefbef0SMatt Redfearn 	}
49*2aefbef0SMatt Redfearn 
50*2aefbef0SMatt Redfearn 	len = strcspn(buf, "\n");
51*2aefbef0SMatt Redfearn 
52*2aefbef0SMatt Redfearn 	p = kstrndup(buf, len, GFP_KERNEL);
53*2aefbef0SMatt Redfearn 	if (!p) {
54*2aefbef0SMatt Redfearn 		err = -ENOMEM;
55*2aefbef0SMatt Redfearn 		goto out;
56*2aefbef0SMatt Redfearn 	}
57*2aefbef0SMatt Redfearn 
58*2aefbef0SMatt Redfearn 	kfree(rproc->firmware);
59*2aefbef0SMatt Redfearn 	rproc->firmware = p;
60*2aefbef0SMatt Redfearn out:
61*2aefbef0SMatt Redfearn 	mutex_unlock(&rproc->lock);
62*2aefbef0SMatt Redfearn 
63*2aefbef0SMatt Redfearn 	return err ? err : count;
64*2aefbef0SMatt Redfearn }
65*2aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware);
66*2aefbef0SMatt Redfearn 
67*2aefbef0SMatt Redfearn /*
68*2aefbef0SMatt Redfearn  * A state-to-string lookup table, for exposing a human readable state
69*2aefbef0SMatt Redfearn  * via sysfs. Always keep in sync with enum rproc_state
70*2aefbef0SMatt Redfearn  */
71*2aefbef0SMatt Redfearn static const char * const rproc_state_string[] = {
72*2aefbef0SMatt Redfearn 	[RPROC_OFFLINE]		= "offline",
73*2aefbef0SMatt Redfearn 	[RPROC_SUSPENDED]	= "suspended",
74*2aefbef0SMatt Redfearn 	[RPROC_RUNNING]		= "running",
75*2aefbef0SMatt Redfearn 	[RPROC_CRASHED]		= "crashed",
76*2aefbef0SMatt Redfearn 	[RPROC_LAST]		= "invalid",
77*2aefbef0SMatt Redfearn };
78*2aefbef0SMatt Redfearn 
79*2aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */
80*2aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr,
81*2aefbef0SMatt Redfearn 			  char *buf)
82*2aefbef0SMatt Redfearn {
83*2aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
84*2aefbef0SMatt Redfearn 	unsigned int state;
85*2aefbef0SMatt Redfearn 
86*2aefbef0SMatt Redfearn 	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
87*2aefbef0SMatt Redfearn 	return sprintf(buf, "%s\n", rproc_state_string[state]);
88*2aefbef0SMatt Redfearn }
89*2aefbef0SMatt Redfearn 
90*2aefbef0SMatt Redfearn /* Change remote processor state via sysfs */
91*2aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev,
92*2aefbef0SMatt Redfearn 			      struct device_attribute *attr,
93*2aefbef0SMatt Redfearn 			      const char *buf, size_t count)
94*2aefbef0SMatt Redfearn {
95*2aefbef0SMatt Redfearn 	struct rproc *rproc = to_rproc(dev);
96*2aefbef0SMatt Redfearn 	int ret = 0;
97*2aefbef0SMatt Redfearn 
98*2aefbef0SMatt Redfearn 	if (sysfs_streq(buf, "start")) {
99*2aefbef0SMatt Redfearn 		if (rproc->state == RPROC_RUNNING)
100*2aefbef0SMatt Redfearn 			return -EBUSY;
101*2aefbef0SMatt Redfearn 
102*2aefbef0SMatt Redfearn 		ret = rproc_boot(rproc);
103*2aefbef0SMatt Redfearn 		if (ret)
104*2aefbef0SMatt Redfearn 			dev_err(&rproc->dev, "Boot failed: %d\n", ret);
105*2aefbef0SMatt Redfearn 	} else if (sysfs_streq(buf, "stop")) {
106*2aefbef0SMatt Redfearn 		if (rproc->state != RPROC_RUNNING)
107*2aefbef0SMatt Redfearn 			return -EINVAL;
108*2aefbef0SMatt Redfearn 
109*2aefbef0SMatt Redfearn 		rproc_shutdown(rproc);
110*2aefbef0SMatt Redfearn 	} else {
111*2aefbef0SMatt Redfearn 		dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
112*2aefbef0SMatt Redfearn 		ret = -EINVAL;
113*2aefbef0SMatt Redfearn 	}
114*2aefbef0SMatt Redfearn 	return ret ? ret : count;
115*2aefbef0SMatt Redfearn }
116*2aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state);
117*2aefbef0SMatt Redfearn 
118*2aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = {
119*2aefbef0SMatt Redfearn 	&dev_attr_firmware.attr,
120*2aefbef0SMatt Redfearn 	&dev_attr_state.attr,
121*2aefbef0SMatt Redfearn 	NULL
122*2aefbef0SMatt Redfearn };
123*2aefbef0SMatt Redfearn 
124*2aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = {
125*2aefbef0SMatt Redfearn 	.attrs = rproc_attrs
126*2aefbef0SMatt Redfearn };
127*2aefbef0SMatt Redfearn 
128*2aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = {
129*2aefbef0SMatt Redfearn 	&rproc_devgroup,
130*2aefbef0SMatt Redfearn 	NULL
131*2aefbef0SMatt Redfearn };
132*2aefbef0SMatt Redfearn 
133*2aefbef0SMatt Redfearn struct class rproc_class = {
134*2aefbef0SMatt Redfearn 	.name		= "remoteproc",
135*2aefbef0SMatt Redfearn 	.dev_groups	= rproc_devgroups,
136*2aefbef0SMatt Redfearn };
137*2aefbef0SMatt Redfearn 
138*2aefbef0SMatt Redfearn int __init rproc_init_sysfs(void)
139*2aefbef0SMatt Redfearn {
140*2aefbef0SMatt Redfearn 	/* create remoteproc device class for sysfs */
141*2aefbef0SMatt Redfearn 	int err = class_register(&rproc_class);
142*2aefbef0SMatt Redfearn 
143*2aefbef0SMatt Redfearn 	if (err)
144*2aefbef0SMatt Redfearn 		pr_err("remoteproc: unable to register class\n");
145*2aefbef0SMatt Redfearn 	return err;
146*2aefbef0SMatt Redfearn }
147*2aefbef0SMatt Redfearn 
148*2aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void)
149*2aefbef0SMatt Redfearn {
150*2aefbef0SMatt Redfearn 	class_unregister(&rproc_class);
151*2aefbef0SMatt Redfearn }
152