.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Remote Processor Framework |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or |
---|
5 | | - * modify it under the terms of the GNU General Public License |
---|
6 | | - * version 2 as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | 4 | */ |
---|
13 | 5 | |
---|
14 | 6 | #include <linux/remoteproc.h> |
---|
| 7 | +#include <linux/slab.h> |
---|
| 8 | +#include <trace/hooks/remoteproc.h> |
---|
15 | 9 | |
---|
16 | 10 | #include "remoteproc_internal.h" |
---|
17 | 11 | |
---|
18 | 12 | #define to_rproc(d) container_of(d, struct rproc, dev) |
---|
| 13 | + |
---|
| 14 | +static ssize_t recovery_show(struct device *dev, |
---|
| 15 | + struct device_attribute *attr, char *buf) |
---|
| 16 | +{ |
---|
| 17 | + struct rproc *rproc = to_rproc(dev); |
---|
| 18 | + |
---|
| 19 | + return sprintf(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n"); |
---|
| 20 | +} |
---|
| 21 | + |
---|
| 22 | +/* |
---|
| 23 | + * By writing to the 'recovery' sysfs entry, we control the behavior of the |
---|
| 24 | + * recovery mechanism dynamically. The default value of this entry is "enabled". |
---|
| 25 | + * |
---|
| 26 | + * The 'recovery' sysfs entry supports these commands: |
---|
| 27 | + * |
---|
| 28 | + * enabled: When enabled, the remote processor will be automatically |
---|
| 29 | + * recovered whenever it crashes. Moreover, if the remote |
---|
| 30 | + * processor crashes while recovery is disabled, it will |
---|
| 31 | + * be automatically recovered too as soon as recovery is enabled. |
---|
| 32 | + * |
---|
| 33 | + * disabled: When disabled, a remote processor will remain in a crashed |
---|
| 34 | + * state if it crashes. This is useful for debugging purposes; |
---|
| 35 | + * without it, debugging a crash is substantially harder. |
---|
| 36 | + * |
---|
| 37 | + * recover: This function will trigger an immediate recovery if the |
---|
| 38 | + * remote processor is in a crashed state, without changing |
---|
| 39 | + * or checking the recovery state (enabled/disabled). |
---|
| 40 | + * This is useful during debugging sessions, when one expects |
---|
| 41 | + * additional crashes to happen after enabling recovery. In this |
---|
| 42 | + * case, enabling recovery will make it hard to debug subsequent |
---|
| 43 | + * crashes, so it's recommended to keep recovery disabled, and |
---|
| 44 | + * instead use the "recover" command as needed. |
---|
| 45 | + */ |
---|
| 46 | +static ssize_t recovery_store(struct device *dev, |
---|
| 47 | + struct device_attribute *attr, |
---|
| 48 | + const char *buf, size_t count) |
---|
| 49 | +{ |
---|
| 50 | + struct rproc *rproc = to_rproc(dev); |
---|
| 51 | + |
---|
| 52 | + if (sysfs_streq(buf, "enabled")) { |
---|
| 53 | + /* change the flag and begin the recovery process if needed */ |
---|
| 54 | + rproc->recovery_disabled = false; |
---|
| 55 | + trace_android_vh_rproc_recovery_set(rproc); |
---|
| 56 | + rproc_trigger_recovery(rproc); |
---|
| 57 | + } else if (sysfs_streq(buf, "disabled")) { |
---|
| 58 | + rproc->recovery_disabled = true; |
---|
| 59 | + trace_android_vh_rproc_recovery_set(rproc); |
---|
| 60 | + } else if (sysfs_streq(buf, "recover")) { |
---|
| 61 | + /* begin the recovery process without changing the flag */ |
---|
| 62 | + rproc_trigger_recovery(rproc); |
---|
| 63 | + } else { |
---|
| 64 | + return -EINVAL; |
---|
| 65 | + } |
---|
| 66 | + |
---|
| 67 | + return count; |
---|
| 68 | +} |
---|
| 69 | +static DEVICE_ATTR_RW(recovery); |
---|
| 70 | + |
---|
| 71 | +/* |
---|
| 72 | + * A coredump-configuration-to-string lookup table, for exposing a |
---|
| 73 | + * human readable configuration via sysfs. Always keep in sync with |
---|
| 74 | + * enum rproc_coredump_mechanism |
---|
| 75 | + */ |
---|
| 76 | +static const char * const rproc_coredump_str[] = { |
---|
| 77 | + [RPROC_COREDUMP_DISABLED] = "disabled", |
---|
| 78 | + [RPROC_COREDUMP_ENABLED] = "enabled", |
---|
| 79 | + [RPROC_COREDUMP_INLINE] = "inline", |
---|
| 80 | +}; |
---|
| 81 | + |
---|
| 82 | +/* Expose the current coredump configuration via debugfs */ |
---|
| 83 | +static ssize_t coredump_show(struct device *dev, |
---|
| 84 | + struct device_attribute *attr, char *buf) |
---|
| 85 | +{ |
---|
| 86 | + struct rproc *rproc = to_rproc(dev); |
---|
| 87 | + |
---|
| 88 | + return sprintf(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]); |
---|
| 89 | +} |
---|
| 90 | + |
---|
| 91 | +/* |
---|
| 92 | + * By writing to the 'coredump' sysfs entry, we control the behavior of the |
---|
| 93 | + * coredump mechanism dynamically. The default value of this entry is "default". |
---|
| 94 | + * |
---|
| 95 | + * The 'coredump' sysfs entry supports these commands: |
---|
| 96 | + * |
---|
| 97 | + * disabled: This is the default coredump mechanism. Recovery will proceed |
---|
| 98 | + * without collecting any dump. |
---|
| 99 | + * |
---|
| 100 | + * default: When the remoteproc crashes the entire coredump will be |
---|
| 101 | + * copied to a separate buffer and exposed to userspace. |
---|
| 102 | + * |
---|
| 103 | + * inline: The coredump will not be copied to a separate buffer and the |
---|
| 104 | + * recovery process will have to wait until data is read by |
---|
| 105 | + * userspace. But this avoid usage of extra memory. |
---|
| 106 | + */ |
---|
| 107 | +static ssize_t coredump_store(struct device *dev, |
---|
| 108 | + struct device_attribute *attr, |
---|
| 109 | + const char *buf, size_t count) |
---|
| 110 | +{ |
---|
| 111 | + struct rproc *rproc = to_rproc(dev); |
---|
| 112 | + |
---|
| 113 | + if (rproc->state == RPROC_CRASHED) { |
---|
| 114 | + dev_err(&rproc->dev, "can't change coredump configuration\n"); |
---|
| 115 | + return -EBUSY; |
---|
| 116 | + } |
---|
| 117 | + |
---|
| 118 | + if (sysfs_streq(buf, "disabled")) { |
---|
| 119 | + rproc->dump_conf = RPROC_COREDUMP_DISABLED; |
---|
| 120 | + } else if (sysfs_streq(buf, "enabled")) { |
---|
| 121 | + rproc->dump_conf = RPROC_COREDUMP_ENABLED; |
---|
| 122 | + } else if (sysfs_streq(buf, "inline")) { |
---|
| 123 | + rproc->dump_conf = RPROC_COREDUMP_INLINE; |
---|
| 124 | + } else { |
---|
| 125 | + dev_err(&rproc->dev, "Invalid coredump configuration\n"); |
---|
| 126 | + return -EINVAL; |
---|
| 127 | + } |
---|
| 128 | + |
---|
| 129 | + return count; |
---|
| 130 | +} |
---|
| 131 | +static DEVICE_ATTR_RW(coredump); |
---|
19 | 132 | |
---|
20 | 133 | /* Expose the loaded / running firmware name via sysfs */ |
---|
21 | 134 | static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, |
---|
22 | 135 | char *buf) |
---|
23 | 136 | { |
---|
24 | 137 | struct rproc *rproc = to_rproc(dev); |
---|
| 138 | + const char *firmware = rproc->firmware; |
---|
25 | 139 | |
---|
26 | | - return sprintf(buf, "%s\n", rproc->firmware); |
---|
| 140 | + /* |
---|
| 141 | + * If the remote processor has been started by an external |
---|
| 142 | + * entity we have no idea of what image it is running. As such |
---|
| 143 | + * simply display a generic string rather then rproc->firmware. |
---|
| 144 | + * |
---|
| 145 | + * Here we rely on the autonomous flag because a remote processor |
---|
| 146 | + * may have been attached to and currently in a running state. |
---|
| 147 | + */ |
---|
| 148 | + if (rproc->autonomous) |
---|
| 149 | + firmware = "unknown"; |
---|
| 150 | + |
---|
| 151 | + return sprintf(buf, "%s\n", firmware); |
---|
27 | 152 | } |
---|
28 | 153 | |
---|
29 | 154 | /* Change firmware name via sysfs */ |
---|
.. | .. |
---|
32 | 157 | const char *buf, size_t count) |
---|
33 | 158 | { |
---|
34 | 159 | struct rproc *rproc = to_rproc(dev); |
---|
35 | | - char *p; |
---|
36 | | - int err, len = count; |
---|
| 160 | + int err; |
---|
37 | 161 | |
---|
38 | | - err = mutex_lock_interruptible(&rproc->lock); |
---|
39 | | - if (err) { |
---|
40 | | - dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err); |
---|
41 | | - return -EINVAL; |
---|
42 | | - } |
---|
43 | | - |
---|
44 | | - if (rproc->state != RPROC_OFFLINE) { |
---|
45 | | - dev_err(dev, "can't change firmware while running\n"); |
---|
46 | | - err = -EBUSY; |
---|
47 | | - goto out; |
---|
48 | | - } |
---|
49 | | - |
---|
50 | | - len = strcspn(buf, "\n"); |
---|
51 | | - if (!len) { |
---|
52 | | - dev_err(dev, "can't provide a NULL firmware\n"); |
---|
53 | | - err = -EINVAL; |
---|
54 | | - goto out; |
---|
55 | | - } |
---|
56 | | - |
---|
57 | | - p = kstrndup(buf, len, GFP_KERNEL); |
---|
58 | | - if (!p) { |
---|
59 | | - err = -ENOMEM; |
---|
60 | | - goto out; |
---|
61 | | - } |
---|
62 | | - |
---|
63 | | - kfree(rproc->firmware); |
---|
64 | | - rproc->firmware = p; |
---|
65 | | -out: |
---|
66 | | - mutex_unlock(&rproc->lock); |
---|
| 162 | + err = rproc_set_firmware(rproc, buf); |
---|
67 | 163 | |
---|
68 | 164 | return err ? err : count; |
---|
69 | 165 | } |
---|
.. | .. |
---|
79 | 175 | [RPROC_RUNNING] = "running", |
---|
80 | 176 | [RPROC_CRASHED] = "crashed", |
---|
81 | 177 | [RPROC_DELETED] = "deleted", |
---|
| 178 | + [RPROC_DETACHED] = "detached", |
---|
82 | 179 | [RPROC_LAST] = "invalid", |
---|
83 | 180 | }; |
---|
84 | 181 | |
---|
.. | .. |
---|
121 | 218 | } |
---|
122 | 219 | static DEVICE_ATTR_RW(state); |
---|
123 | 220 | |
---|
| 221 | +/* Expose the name of the remote processor via sysfs */ |
---|
| 222 | +static ssize_t name_show(struct device *dev, struct device_attribute *attr, |
---|
| 223 | + char *buf) |
---|
| 224 | +{ |
---|
| 225 | + struct rproc *rproc = to_rproc(dev); |
---|
| 226 | + |
---|
| 227 | + return sprintf(buf, "%s\n", rproc->name); |
---|
| 228 | +} |
---|
| 229 | +static DEVICE_ATTR_RO(name); |
---|
| 230 | + |
---|
124 | 231 | static struct attribute *rproc_attrs[] = { |
---|
| 232 | + &dev_attr_coredump.attr, |
---|
| 233 | + &dev_attr_recovery.attr, |
---|
125 | 234 | &dev_attr_firmware.attr, |
---|
126 | 235 | &dev_attr_state.attr, |
---|
| 236 | + &dev_attr_name.attr, |
---|
127 | 237 | NULL |
---|
128 | 238 | }; |
---|
129 | 239 | |
---|