]> Git Repo - linux.git/blob - drivers/base/firmware_loader/sysfs_upload.c
i3c: mipi-i3c-hci: Fix DAT/DCT entry sizes
[linux.git] / drivers / base / firmware_loader / sysfs_upload.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/firmware.h>
4 #include <linux/module.h>
5 #include <linux/slab.h>
6
7 #include "sysfs_upload.h"
8
9 /*
10  * Support for user-space to initiate a firmware upload to a device.
11  */
12
13 static const char * const fw_upload_prog_str[] = {
14         [FW_UPLOAD_PROG_IDLE]         = "idle",
15         [FW_UPLOAD_PROG_RECEIVING]    = "receiving",
16         [FW_UPLOAD_PROG_PREPARING]    = "preparing",
17         [FW_UPLOAD_PROG_TRANSFERRING] = "transferring",
18         [FW_UPLOAD_PROG_PROGRAMMING]  = "programming"
19 };
20
21 static const char * const fw_upload_err_str[] = {
22         [FW_UPLOAD_ERR_NONE]         = "none",
23         [FW_UPLOAD_ERR_HW_ERROR]     = "hw-error",
24         [FW_UPLOAD_ERR_TIMEOUT]      = "timeout",
25         [FW_UPLOAD_ERR_CANCELED]     = "user-abort",
26         [FW_UPLOAD_ERR_BUSY]         = "device-busy",
27         [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size",
28         [FW_UPLOAD_ERR_RW_ERROR]     = "read-write-error",
29         [FW_UPLOAD_ERR_WEAROUT]      = "flash-wearout",
30 };
31
32 static const char *fw_upload_progress(struct device *dev,
33                                       enum fw_upload_prog prog)
34 {
35         const char *status = "unknown-status";
36
37         if (prog < FW_UPLOAD_PROG_MAX)
38                 status = fw_upload_prog_str[prog];
39         else
40                 dev_err(dev, "Invalid status during secure update: %d\n", prog);
41
42         return status;
43 }
44
45 static const char *fw_upload_error(struct device *dev,
46                                    enum fw_upload_err err_code)
47 {
48         const char *error = "unknown-error";
49
50         if (err_code < FW_UPLOAD_ERR_MAX)
51                 error = fw_upload_err_str[err_code];
52         else
53                 dev_err(dev, "Invalid error code during secure update: %d\n",
54                         err_code);
55
56         return error;
57 }
58
59 static ssize_t
60 status_show(struct device *dev, struct device_attribute *attr, char *buf)
61 {
62         struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv;
63
64         return sysfs_emit(buf, "%s\n", fw_upload_progress(dev, fwlp->progress));
65 }
66 DEVICE_ATTR_RO(status);
67
68 static ssize_t
69 error_show(struct device *dev, struct device_attribute *attr, char *buf)
70 {
71         struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv;
72         int ret;
73
74         mutex_lock(&fwlp->lock);
75
76         if (fwlp->progress != FW_UPLOAD_PROG_IDLE)
77                 ret = -EBUSY;
78         else if (!fwlp->err_code)
79                 ret = 0;
80         else
81                 ret = sysfs_emit(buf, "%s:%s\n",
82                                  fw_upload_progress(dev, fwlp->err_progress),
83                                  fw_upload_error(dev, fwlp->err_code));
84
85         mutex_unlock(&fwlp->lock);
86
87         return ret;
88 }
89 DEVICE_ATTR_RO(error);
90
91 static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
92                             const char *buf, size_t count)
93 {
94         struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv;
95         int ret = count;
96         bool cancel;
97
98         if (kstrtobool(buf, &cancel) || !cancel)
99                 return -EINVAL;
100
101         mutex_lock(&fwlp->lock);
102         if (fwlp->progress == FW_UPLOAD_PROG_IDLE)
103                 ret = -ENODEV;
104
105         fwlp->ops->cancel(fwlp->fw_upload);
106         mutex_unlock(&fwlp->lock);
107
108         return ret;
109 }
110 DEVICE_ATTR_WO(cancel);
111
112 static ssize_t remaining_size_show(struct device *dev,
113                                    struct device_attribute *attr, char *buf)
114 {
115         struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv;
116
117         return sysfs_emit(buf, "%u\n", fwlp->remaining_size);
118 }
119 DEVICE_ATTR_RO(remaining_size);
120
121 umode_t
122 fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n)
123 {
124         static struct fw_sysfs *fw_sysfs;
125
126         fw_sysfs = to_fw_sysfs(kobj_to_dev(kobj));
127
128         if (fw_sysfs->fw_upload_priv || attr == &dev_attr_loading.attr)
129                 return attr->mode;
130
131         return 0;
132 }
133
134 static void fw_upload_update_progress(struct fw_upload_priv *fwlp,
135                                       enum fw_upload_prog new_progress)
136 {
137         mutex_lock(&fwlp->lock);
138         fwlp->progress = new_progress;
139         mutex_unlock(&fwlp->lock);
140 }
141
142 static void fw_upload_set_error(struct fw_upload_priv *fwlp,
143                                 enum fw_upload_err err_code)
144 {
145         mutex_lock(&fwlp->lock);
146         fwlp->err_progress = fwlp->progress;
147         fwlp->err_code = err_code;
148         mutex_unlock(&fwlp->lock);
149 }
150
151 static void fw_upload_prog_complete(struct fw_upload_priv *fwlp)
152 {
153         mutex_lock(&fwlp->lock);
154         fwlp->progress = FW_UPLOAD_PROG_IDLE;
155         mutex_unlock(&fwlp->lock);
156 }
157
158 static void fw_upload_main(struct work_struct *work)
159 {
160         struct fw_upload_priv *fwlp;
161         struct fw_sysfs *fw_sysfs;
162         u32 written = 0, offset = 0;
163         enum fw_upload_err ret;
164         struct device *fw_dev;
165         struct fw_upload *fwl;
166
167         fwlp = container_of(work, struct fw_upload_priv, work);
168         fwl = fwlp->fw_upload;
169         fw_sysfs = (struct fw_sysfs *)fwl->priv;
170         fw_dev = &fw_sysfs->dev;
171
172         fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_PREPARING);
173         ret = fwlp->ops->prepare(fwl, fwlp->data, fwlp->remaining_size);
174         if (ret != FW_UPLOAD_ERR_NONE) {
175                 fw_upload_set_error(fwlp, ret);
176                 goto putdev_exit;
177         }
178
179         fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_TRANSFERRING);
180         while (fwlp->remaining_size) {
181                 ret = fwlp->ops->write(fwl, fwlp->data, offset,
182                                         fwlp->remaining_size, &written);
183                 if (ret != FW_UPLOAD_ERR_NONE || !written) {
184                         if (ret == FW_UPLOAD_ERR_NONE) {
185                                 dev_warn(fw_dev, "write-op wrote zero data\n");
186                                 ret = FW_UPLOAD_ERR_RW_ERROR;
187                         }
188                         fw_upload_set_error(fwlp, ret);
189                         goto done;
190                 }
191
192                 fwlp->remaining_size -= written;
193                 offset += written;
194         }
195
196         fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_PROGRAMMING);
197         ret = fwlp->ops->poll_complete(fwl);
198         if (ret != FW_UPLOAD_ERR_NONE)
199                 fw_upload_set_error(fwlp, ret);
200
201 done:
202         if (fwlp->ops->cleanup)
203                 fwlp->ops->cleanup(fwl);
204
205 putdev_exit:
206         put_device(fw_dev->parent);
207
208         /*
209          * Note: fwlp->remaining_size is left unmodified here to provide
210          * additional information on errors. It will be reinitialized when
211          * the next firmeware upload begins.
212          */
213         mutex_lock(&fw_lock);
214         fw_free_paged_buf(fw_sysfs->fw_priv);
215         fw_state_init(fw_sysfs->fw_priv);
216         mutex_unlock(&fw_lock);
217         fwlp->data = NULL;
218         fw_upload_prog_complete(fwlp);
219 }
220
221 /*
222  * Start a worker thread to upload data to the parent driver.
223  * Must be called with fw_lock held.
224  */
225 int fw_upload_start(struct fw_sysfs *fw_sysfs)
226 {
227         struct fw_priv *fw_priv = fw_sysfs->fw_priv;
228         struct device *fw_dev = &fw_sysfs->dev;
229         struct fw_upload_priv *fwlp;
230
231         if (!fw_sysfs->fw_upload_priv)
232                 return 0;
233
234         if (!fw_priv->size) {
235                 fw_free_paged_buf(fw_priv);
236                 fw_state_init(fw_sysfs->fw_priv);
237                 return 0;
238         }
239
240         fwlp = fw_sysfs->fw_upload_priv;
241         mutex_lock(&fwlp->lock);
242
243         /* Do not interfere with an on-going fw_upload */
244         if (fwlp->progress != FW_UPLOAD_PROG_IDLE) {
245                 mutex_unlock(&fwlp->lock);
246                 return -EBUSY;
247         }
248
249         get_device(fw_dev->parent); /* released in fw_upload_main */
250
251         fwlp->progress = FW_UPLOAD_PROG_RECEIVING;
252         fwlp->err_code = 0;
253         fwlp->remaining_size = fw_priv->size;
254         fwlp->data = fw_priv->data;
255
256         pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n",
257                  __func__, fw_priv->fw_name,
258                  fw_priv, fw_priv->data,
259                  (unsigned int)fw_priv->size);
260
261         queue_work(system_long_wq, &fwlp->work);
262         mutex_unlock(&fwlp->lock);
263
264         return 0;
265 }
266
267 void fw_upload_free(struct fw_sysfs *fw_sysfs)
268 {
269         struct fw_upload_priv *fw_upload_priv = fw_sysfs->fw_upload_priv;
270
271         free_fw_priv(fw_sysfs->fw_priv);
272         kfree(fw_upload_priv->fw_upload);
273         kfree(fw_upload_priv);
274 }
275
276 /**
277  * firmware_upload_register() - register for the firmware upload sysfs API
278  * @module: kernel module of this device
279  * @parent: parent device instantiating firmware upload
280  * @name: firmware name to be associated with this device
281  * @ops: pointer to structure of firmware upload ops
282  * @dd_handle: pointer to parent driver private data
283  *
284  *      @name must be unique among all users of firmware upload. The firmware
285  *      sysfs files for this device will be found at /sys/class/firmware/@name.
286  *
287  *      Return: struct fw_upload pointer or ERR_PTR()
288  *
289  **/
290 struct fw_upload *
291 firmware_upload_register(struct module *module, struct device *parent,
292                          const char *name, const struct fw_upload_ops *ops,
293                          void *dd_handle)
294 {
295         u32 opt_flags = FW_OPT_NOCACHE;
296         struct fw_upload *fw_upload;
297         struct fw_upload_priv *fw_upload_priv;
298         struct fw_sysfs *fw_sysfs;
299         struct fw_priv *fw_priv;
300         struct device *fw_dev;
301         int ret;
302
303         if (!name || name[0] == '\0')
304                 return ERR_PTR(-EINVAL);
305
306         if (!ops || !ops->cancel || !ops->prepare ||
307             !ops->write || !ops->poll_complete) {
308                 dev_err(parent, "Attempt to register without all required ops\n");
309                 return ERR_PTR(-EINVAL);
310         }
311
312         if (!try_module_get(module))
313                 return ERR_PTR(-EFAULT);
314
315         fw_upload = kzalloc(sizeof(*fw_upload), GFP_KERNEL);
316         if (!fw_upload) {
317                 ret = -ENOMEM;
318                 goto exit_module_put;
319         }
320
321         fw_upload_priv = kzalloc(sizeof(*fw_upload_priv), GFP_KERNEL);
322         if (!fw_upload_priv) {
323                 ret = -ENOMEM;
324                 goto free_fw_upload;
325         }
326
327         fw_upload_priv->fw_upload = fw_upload;
328         fw_upload_priv->ops = ops;
329         mutex_init(&fw_upload_priv->lock);
330         fw_upload_priv->module = module;
331         fw_upload_priv->name = name;
332         fw_upload_priv->err_code = 0;
333         fw_upload_priv->progress = FW_UPLOAD_PROG_IDLE;
334         INIT_WORK(&fw_upload_priv->work, fw_upload_main);
335         fw_upload->dd_handle = dd_handle;
336
337         fw_sysfs = fw_create_instance(NULL, name, parent, opt_flags);
338         if (IS_ERR(fw_sysfs)) {
339                 ret = PTR_ERR(fw_sysfs);
340                 goto free_fw_upload_priv;
341         }
342         fw_upload->priv = fw_sysfs;
343         fw_sysfs->fw_upload_priv = fw_upload_priv;
344         fw_dev = &fw_sysfs->dev;
345
346         ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv,  NULL, 0, 0,
347                                    FW_OPT_NOCACHE);
348         if (ret != 0) {
349                 if (ret > 0)
350                         ret = -EINVAL;
351                 goto free_fw_sysfs;
352         }
353         fw_priv->is_paged_buf = true;
354         fw_sysfs->fw_priv = fw_priv;
355
356         ret = device_add(fw_dev);
357         if (ret) {
358                 dev_err(fw_dev, "%s: device_register failed\n", __func__);
359                 put_device(fw_dev);
360                 goto exit_module_put;
361         }
362
363         return fw_upload;
364
365 free_fw_sysfs:
366         kfree(fw_sysfs);
367
368 free_fw_upload_priv:
369         kfree(fw_upload_priv);
370
371 free_fw_upload:
372         kfree(fw_upload);
373
374 exit_module_put:
375         module_put(module);
376
377         return ERR_PTR(ret);
378 }
379 EXPORT_SYMBOL_GPL(firmware_upload_register);
380
381 /**
382  * firmware_upload_unregister() - Unregister firmware upload interface
383  * @fw_upload: pointer to struct fw_upload
384  **/
385 void firmware_upload_unregister(struct fw_upload *fw_upload)
386 {
387         struct fw_sysfs *fw_sysfs = fw_upload->priv;
388         struct fw_upload_priv *fw_upload_priv = fw_sysfs->fw_upload_priv;
389         struct module *module = fw_upload_priv->module;
390
391         mutex_lock(&fw_upload_priv->lock);
392         if (fw_upload_priv->progress == FW_UPLOAD_PROG_IDLE) {
393                 mutex_unlock(&fw_upload_priv->lock);
394                 goto unregister;
395         }
396
397         fw_upload_priv->ops->cancel(fw_upload);
398         mutex_unlock(&fw_upload_priv->lock);
399
400         /* Ensure lower-level device-driver is finished */
401         flush_work(&fw_upload_priv->work);
402
403 unregister:
404         device_unregister(&fw_sysfs->dev);
405         module_put(module);
406 }
407 EXPORT_SYMBOL_GPL(firmware_upload_unregister);
This page took 0.05439 seconds and 4 git commands to generate.