GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / staging / greybus / fw-management.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Greybus Firmware Management Protocol Driver.
4  *
5  * Copyright 2016 Google Inc.
6  * Copyright 2016 Linaro Ltd.
7  */
8
9 #include <linux/cdev.h>
10 #include <linux/completion.h>
11 #include <linux/firmware.h>
12 #include <linux/fs.h>
13 #include <linux/idr.h>
14 #include <linux/ioctl.h>
15 #include <linux/uaccess.h>
16
17 #include "firmware.h"
18 #include "greybus_firmware.h"
19 #include "greybus.h"
20
21 #define FW_MGMT_TIMEOUT_MS              1000
22
23 struct fw_mgmt {
24         struct device           *parent;
25         struct gb_connection    *connection;
26         struct kref             kref;
27         struct list_head        node;
28
29         /* Common id-map for interface and backend firmware requests */
30         struct ida              id_map;
31         struct mutex            mutex;
32         struct completion       completion;
33         struct cdev             cdev;
34         struct device           *class_device;
35         dev_t                   dev_num;
36         unsigned int            timeout_jiffies;
37         bool                    disabled; /* connection getting disabled */
38
39         /* Interface Firmware specific fields */
40         bool                    mode_switch_started;
41         bool                    intf_fw_loaded;
42         u8                      intf_fw_request_id;
43         u8                      intf_fw_status;
44         u16                     intf_fw_major;
45         u16                     intf_fw_minor;
46
47         /* Backend Firmware specific fields */
48         u8                      backend_fw_request_id;
49         u8                      backend_fw_status;
50 };
51
52 /*
53  * Number of minor devices this driver supports.
54  * There will be exactly one required per Interface.
55  */
56 #define NUM_MINORS              U8_MAX
57
58 static struct class *fw_mgmt_class;
59 static dev_t fw_mgmt_dev_num;
60 static DEFINE_IDA(fw_mgmt_minors_map);
61 static LIST_HEAD(fw_mgmt_list);
62 static DEFINE_MUTEX(list_mutex);
63
64 static void fw_mgmt_kref_release(struct kref *kref)
65 {
66         struct fw_mgmt *fw_mgmt = container_of(kref, struct fw_mgmt, kref);
67
68         ida_destroy(&fw_mgmt->id_map);
69         kfree(fw_mgmt);
70 }
71
72 /*
73  * All users of fw_mgmt take a reference (from within list_mutex lock), before
74  * they get a pointer to play with. And the structure will be freed only after
75  * the last user has put the reference to it.
76  */
77 static void put_fw_mgmt(struct fw_mgmt *fw_mgmt)
78 {
79         kref_put(&fw_mgmt->kref, fw_mgmt_kref_release);
80 }
81
82 /* Caller must call put_fw_mgmt() after using struct fw_mgmt */
83 static struct fw_mgmt *get_fw_mgmt(struct cdev *cdev)
84 {
85         struct fw_mgmt *fw_mgmt;
86
87         mutex_lock(&list_mutex);
88
89         list_for_each_entry(fw_mgmt, &fw_mgmt_list, node) {
90                 if (&fw_mgmt->cdev == cdev) {
91                         kref_get(&fw_mgmt->kref);
92                         goto unlock;
93                 }
94         }
95
96         fw_mgmt = NULL;
97
98 unlock:
99         mutex_unlock(&list_mutex);
100
101         return fw_mgmt;
102 }
103
104 static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt,
105                 struct fw_mgmt_ioc_get_intf_version *fw_info)
106 {
107         struct gb_connection *connection = fw_mgmt->connection;
108         struct gb_fw_mgmt_interface_fw_version_response response;
109         int ret;
110
111         ret = gb_operation_sync(connection,
112                                 GB_FW_MGMT_TYPE_INTERFACE_FW_VERSION, NULL, 0,
113                                 &response, sizeof(response));
114         if (ret) {
115                 dev_err(fw_mgmt->parent,
116                         "failed to get interface firmware version (%d)\n", ret);
117                 return ret;
118         }
119
120         fw_info->major = le16_to_cpu(response.major);
121         fw_info->minor = le16_to_cpu(response.minor);
122
123         strncpy(fw_info->firmware_tag, response.firmware_tag,
124                 GB_FIRMWARE_TAG_MAX_SIZE);
125
126         /*
127          * The firmware-tag should be NULL terminated, otherwise throw error but
128          * don't fail.
129          */
130         if (fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
131                 dev_err(fw_mgmt->parent,
132                         "fw-version: firmware-tag is not NULL terminated\n");
133                 fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] = '\0';
134         }
135
136         return 0;
137 }
138
139 static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
140                                                u8 load_method, const char *tag)
141 {
142         struct gb_fw_mgmt_load_and_validate_fw_request request;
143         int ret;
144
145         if (load_method != GB_FW_LOAD_METHOD_UNIPRO &&
146             load_method != GB_FW_LOAD_METHOD_INTERNAL) {
147                 dev_err(fw_mgmt->parent,
148                         "invalid load-method (%d)\n", load_method);
149                 return -EINVAL;
150         }
151
152         request.load_method = load_method;
153         strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
154
155         /*
156          * The firmware-tag should be NULL terminated, otherwise throw error and
157          * fail.
158          */
159         if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
160                 dev_err(fw_mgmt->parent, "load-and-validate: firmware-tag is not NULL terminated\n");
161                 return -EINVAL;
162         }
163
164         /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
165         ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
166         if (ret < 0) {
167                 dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
168                         ret);
169                 return ret;
170         }
171
172         fw_mgmt->intf_fw_request_id = ret;
173         fw_mgmt->intf_fw_loaded = false;
174         request.request_id = ret;
175
176         ret = gb_operation_sync(fw_mgmt->connection,
177                                 GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW, &request,
178                                 sizeof(request), NULL, 0);
179         if (ret) {
180                 ida_simple_remove(&fw_mgmt->id_map,
181                                   fw_mgmt->intf_fw_request_id);
182                 fw_mgmt->intf_fw_request_id = 0;
183                 dev_err(fw_mgmt->parent,
184                         "load and validate firmware request failed (%d)\n",
185                         ret);
186                 return ret;
187         }
188
189         return 0;
190 }
191
192 static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op)
193 {
194         struct gb_connection *connection = op->connection;
195         struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
196         struct gb_fw_mgmt_loaded_fw_request *request;
197
198         /* No pending load and validate request ? */
199         if (!fw_mgmt->intf_fw_request_id) {
200                 dev_err(fw_mgmt->parent,
201                         "unexpected firmware loaded request received\n");
202                 return -ENODEV;
203         }
204
205         if (op->request->payload_size != sizeof(*request)) {
206                 dev_err(fw_mgmt->parent, "illegal size of firmware loaded request (%zu != %zu)\n",
207                         op->request->payload_size, sizeof(*request));
208                 return -EINVAL;
209         }
210
211         request = op->request->payload;
212
213         /* Invalid request-id ? */
214         if (request->request_id != fw_mgmt->intf_fw_request_id) {
215                 dev_err(fw_mgmt->parent, "invalid request id for firmware loaded request (%02u != %02u)\n",
216                         fw_mgmt->intf_fw_request_id, request->request_id);
217                 return -ENODEV;
218         }
219
220         ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
221         fw_mgmt->intf_fw_request_id = 0;
222         fw_mgmt->intf_fw_status = request->status;
223         fw_mgmt->intf_fw_major = le16_to_cpu(request->major);
224         fw_mgmt->intf_fw_minor = le16_to_cpu(request->minor);
225
226         if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_FAILED)
227                 dev_err(fw_mgmt->parent,
228                         "failed to load interface firmware, status:%02x\n",
229                         fw_mgmt->intf_fw_status);
230         else if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_VALIDATION_FAILED)
231                 dev_err(fw_mgmt->parent,
232                         "failed to validate interface firmware, status:%02x\n",
233                         fw_mgmt->intf_fw_status);
234         else
235                 fw_mgmt->intf_fw_loaded = true;
236
237         complete(&fw_mgmt->completion);
238
239         return 0;
240 }
241
242 static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt,
243                 struct fw_mgmt_ioc_get_backend_version *fw_info)
244 {
245         struct gb_connection *connection = fw_mgmt->connection;
246         struct gb_fw_mgmt_backend_fw_version_request request;
247         struct gb_fw_mgmt_backend_fw_version_response response;
248         int ret;
249
250         strncpy(request.firmware_tag, fw_info->firmware_tag,
251                 GB_FIRMWARE_TAG_MAX_SIZE);
252
253         /*
254          * The firmware-tag should be NULL terminated, otherwise throw error and
255          * fail.
256          */
257         if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
258                 dev_err(fw_mgmt->parent, "backend-version: firmware-tag is not NULL terminated\n");
259                 return -EINVAL;
260         }
261
262         ret = gb_operation_sync(connection,
263                                 GB_FW_MGMT_TYPE_BACKEND_FW_VERSION, &request,
264                                 sizeof(request), &response, sizeof(response));
265         if (ret) {
266                 dev_err(fw_mgmt->parent, "failed to get version of %s backend firmware (%d)\n",
267                         fw_info->firmware_tag, ret);
268                 return ret;
269         }
270
271         fw_info->status = response.status;
272
273         /* Reset version as that should be non-zero only for success case */
274         fw_info->major = 0;
275         fw_info->minor = 0;
276
277         switch (fw_info->status) {
278         case GB_FW_BACKEND_VERSION_STATUS_SUCCESS:
279                 fw_info->major = le16_to_cpu(response.major);
280                 fw_info->minor = le16_to_cpu(response.minor);
281                 break;
282         case GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE:
283         case GB_FW_BACKEND_VERSION_STATUS_RETRY:
284                 break;
285         case GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED:
286                 dev_err(fw_mgmt->parent,
287                         "Firmware with tag %s is not supported by Interface\n",
288                         fw_info->firmware_tag);
289                 break;
290         default:
291                 dev_err(fw_mgmt->parent, "Invalid status received: %u\n",
292                         fw_info->status);
293         }
294
295         return 0;
296 }
297
298 static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
299                                                char *tag)
300 {
301         struct gb_fw_mgmt_backend_fw_update_request request;
302         int ret;
303
304         strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
305
306         /*
307          * The firmware-tag should be NULL terminated, otherwise throw error and
308          * fail.
309          */
310         if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
311                 dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n");
312                 return -EINVAL;
313         }
314
315         /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
316         ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
317         if (ret < 0) {
318                 dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
319                         ret);
320                 return ret;
321         }
322
323         fw_mgmt->backend_fw_request_id = ret;
324         request.request_id = ret;
325
326         ret = gb_operation_sync(fw_mgmt->connection,
327                                 GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE, &request,
328                                 sizeof(request), NULL, 0);
329         if (ret) {
330                 ida_simple_remove(&fw_mgmt->id_map,
331                                   fw_mgmt->backend_fw_request_id);
332                 fw_mgmt->backend_fw_request_id = 0;
333                 dev_err(fw_mgmt->parent,
334                         "backend %s firmware update request failed (%d)\n", tag,
335                         ret);
336                 return ret;
337         }
338
339         return 0;
340 }
341
342 static int fw_mgmt_backend_fw_updated_operation(struct gb_operation *op)
343 {
344         struct gb_connection *connection = op->connection;
345         struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
346         struct gb_fw_mgmt_backend_fw_updated_request *request;
347
348         /* No pending load and validate request ? */
349         if (!fw_mgmt->backend_fw_request_id) {
350                 dev_err(fw_mgmt->parent, "unexpected backend firmware updated request received\n");
351                 return -ENODEV;
352         }
353
354         if (op->request->payload_size != sizeof(*request)) {
355                 dev_err(fw_mgmt->parent, "illegal size of backend firmware updated request (%zu != %zu)\n",
356                         op->request->payload_size, sizeof(*request));
357                 return -EINVAL;
358         }
359
360         request = op->request->payload;
361
362         /* Invalid request-id ? */
363         if (request->request_id != fw_mgmt->backend_fw_request_id) {
364                 dev_err(fw_mgmt->parent, "invalid request id for backend firmware updated request (%02u != %02u)\n",
365                         fw_mgmt->backend_fw_request_id, request->request_id);
366                 return -ENODEV;
367         }
368
369         ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
370         fw_mgmt->backend_fw_request_id = 0;
371         fw_mgmt->backend_fw_status = request->status;
372
373         if ((fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_SUCCESS) &&
374             (fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_RETRY))
375                 dev_err(fw_mgmt->parent,
376                         "failed to load backend firmware: %02x\n",
377                         fw_mgmt->backend_fw_status);
378
379         complete(&fw_mgmt->completion);
380
381         return 0;
382 }
383
384 /* Char device fops */
385
386 static int fw_mgmt_open(struct inode *inode, struct file *file)
387 {
388         struct fw_mgmt *fw_mgmt = get_fw_mgmt(inode->i_cdev);
389
390         /* fw_mgmt structure can't get freed until file descriptor is closed */
391         if (fw_mgmt) {
392                 file->private_data = fw_mgmt;
393                 return 0;
394         }
395
396         return -ENODEV;
397 }
398
399 static int fw_mgmt_release(struct inode *inode, struct file *file)
400 {
401         struct fw_mgmt *fw_mgmt = file->private_data;
402
403         put_fw_mgmt(fw_mgmt);
404         return 0;
405 }
406
407 static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd,
408                          void __user *buf)
409 {
410         struct fw_mgmt_ioc_get_intf_version intf_fw_info;
411         struct fw_mgmt_ioc_get_backend_version backend_fw_info;
412         struct fw_mgmt_ioc_intf_load_and_validate intf_load;
413         struct fw_mgmt_ioc_backend_fw_update backend_update;
414         unsigned int timeout;
415         int ret;
416
417         /* Reject any operations after mode-switch has started */
418         if (fw_mgmt->mode_switch_started)
419                 return -EBUSY;
420
421         switch (cmd) {
422         case FW_MGMT_IOC_GET_INTF_FW:
423                 ret = fw_mgmt_interface_fw_version_operation(fw_mgmt,
424                                                              &intf_fw_info);
425                 if (ret)
426                         return ret;
427
428                 if (copy_to_user(buf, &intf_fw_info, sizeof(intf_fw_info)))
429                         return -EFAULT;
430
431                 return 0;
432         case FW_MGMT_IOC_GET_BACKEND_FW:
433                 if (copy_from_user(&backend_fw_info, buf,
434                                    sizeof(backend_fw_info)))
435                         return -EFAULT;
436
437                 ret = fw_mgmt_backend_fw_version_operation(fw_mgmt,
438                                                            &backend_fw_info);
439                 if (ret)
440                         return ret;
441
442                 if (copy_to_user(buf, &backend_fw_info,
443                                  sizeof(backend_fw_info)))
444                         return -EFAULT;
445
446                 return 0;
447         case FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE:
448                 if (copy_from_user(&intf_load, buf, sizeof(intf_load)))
449                         return -EFAULT;
450
451                 ret = fw_mgmt_load_and_validate_operation(fw_mgmt,
452                                 intf_load.load_method, intf_load.firmware_tag);
453                 if (ret)
454                         return ret;
455
456                 if (!wait_for_completion_timeout(&fw_mgmt->completion,
457                                                  fw_mgmt->timeout_jiffies)) {
458                         dev_err(fw_mgmt->parent, "timed out waiting for firmware load and validation to finish\n");
459                         return -ETIMEDOUT;
460                 }
461
462                 intf_load.status = fw_mgmt->intf_fw_status;
463                 intf_load.major = fw_mgmt->intf_fw_major;
464                 intf_load.minor = fw_mgmt->intf_fw_minor;
465
466                 if (copy_to_user(buf, &intf_load, sizeof(intf_load)))
467                         return -EFAULT;
468
469                 return 0;
470         case FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE:
471                 if (copy_from_user(&backend_update, buf,
472                                    sizeof(backend_update)))
473                         return -EFAULT;
474
475                 ret = fw_mgmt_backend_fw_update_operation(fw_mgmt,
476                                 backend_update.firmware_tag);
477                 if (ret)
478                         return ret;
479
480                 if (!wait_for_completion_timeout(&fw_mgmt->completion,
481                                                  fw_mgmt->timeout_jiffies)) {
482                         dev_err(fw_mgmt->parent, "timed out waiting for backend firmware update to finish\n");
483                         return -ETIMEDOUT;
484                 }
485
486                 backend_update.status = fw_mgmt->backend_fw_status;
487
488                 if (copy_to_user(buf, &backend_update, sizeof(backend_update)))
489                         return -EFAULT;
490
491                 return 0;
492         case FW_MGMT_IOC_SET_TIMEOUT_MS:
493                 if (get_user(timeout, (unsigned int __user *)buf))
494                         return -EFAULT;
495
496                 if (!timeout) {
497                         dev_err(fw_mgmt->parent, "timeout can't be zero\n");
498                         return -EINVAL;
499                 }
500
501                 fw_mgmt->timeout_jiffies = msecs_to_jiffies(timeout);
502
503                 return 0;
504         case FW_MGMT_IOC_MODE_SWITCH:
505                 if (!fw_mgmt->intf_fw_loaded) {
506                         dev_err(fw_mgmt->parent,
507                                 "Firmware not loaded for mode-switch\n");
508                         return -EPERM;
509                 }
510
511                 /*
512                  * Disallow new ioctls as the fw-core bundle driver is going to
513                  * get disconnected soon and the character device will get
514                  * removed.
515                  */
516                 fw_mgmt->mode_switch_started = true;
517
518                 ret = gb_interface_request_mode_switch(fw_mgmt->connection->intf);
519                 if (ret) {
520                         dev_err(fw_mgmt->parent, "Mode-switch failed: %d\n",
521                                 ret);
522                         fw_mgmt->mode_switch_started = false;
523                         return ret;
524                 }
525
526                 return 0;
527         default:
528                 return -ENOTTY;
529         }
530 }
531
532 static long fw_mgmt_ioctl_unlocked(struct file *file, unsigned int cmd,
533                                    unsigned long arg)
534 {
535         struct fw_mgmt *fw_mgmt = file->private_data;
536         struct gb_bundle *bundle = fw_mgmt->connection->bundle;
537         int ret = -ENODEV;
538
539         /*
540          * Serialize ioctls.
541          *
542          * We don't want the user to do few operations in parallel. For example,
543          * updating Interface firmware in parallel for the same Interface. There
544          * is no need to do things in parallel for speed and we can avoid having
545          * complicated code for now.
546          *
547          * This is also used to protect ->disabled, which is used to check if
548          * the connection is getting disconnected, so that we don't start any
549          * new operations.
550          */
551         mutex_lock(&fw_mgmt->mutex);
552         if (!fw_mgmt->disabled) {
553                 ret = gb_pm_runtime_get_sync(bundle);
554                 if (!ret) {
555                         ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg);
556                         gb_pm_runtime_put_autosuspend(bundle);
557                 }
558         }
559         mutex_unlock(&fw_mgmt->mutex);
560
561         return ret;
562 }
563
564 static const struct file_operations fw_mgmt_fops = {
565         .owner          = THIS_MODULE,
566         .open           = fw_mgmt_open,
567         .release        = fw_mgmt_release,
568         .unlocked_ioctl = fw_mgmt_ioctl_unlocked,
569 };
570
571 int gb_fw_mgmt_request_handler(struct gb_operation *op)
572 {
573         u8 type = op->type;
574
575         switch (type) {
576         case GB_FW_MGMT_TYPE_LOADED_FW:
577                 return fw_mgmt_interface_fw_loaded_operation(op);
578         case GB_FW_MGMT_TYPE_BACKEND_FW_UPDATED:
579                 return fw_mgmt_backend_fw_updated_operation(op);
580         default:
581                 dev_err(&op->connection->bundle->dev,
582                         "unsupported request: %u\n", type);
583                 return -EINVAL;
584         }
585 }
586
587 int gb_fw_mgmt_connection_init(struct gb_connection *connection)
588 {
589         struct fw_mgmt *fw_mgmt;
590         int ret, minor;
591
592         if (!connection)
593                 return 0;
594
595         fw_mgmt = kzalloc(sizeof(*fw_mgmt), GFP_KERNEL);
596         if (!fw_mgmt)
597                 return -ENOMEM;
598
599         fw_mgmt->parent = &connection->bundle->dev;
600         fw_mgmt->timeout_jiffies = msecs_to_jiffies(FW_MGMT_TIMEOUT_MS);
601         fw_mgmt->connection = connection;
602
603         gb_connection_set_data(connection, fw_mgmt);
604         init_completion(&fw_mgmt->completion);
605         ida_init(&fw_mgmt->id_map);
606         mutex_init(&fw_mgmt->mutex);
607         kref_init(&fw_mgmt->kref);
608
609         mutex_lock(&list_mutex);
610         list_add(&fw_mgmt->node, &fw_mgmt_list);
611         mutex_unlock(&list_mutex);
612
613         ret = gb_connection_enable(connection);
614         if (ret)
615                 goto err_list_del;
616
617         minor = ida_simple_get(&fw_mgmt_minors_map, 0, NUM_MINORS, GFP_KERNEL);
618         if (minor < 0) {
619                 ret = minor;
620                 goto err_connection_disable;
621         }
622
623         /* Add a char device to allow userspace to interact with fw-mgmt */
624         fw_mgmt->dev_num = MKDEV(MAJOR(fw_mgmt_dev_num), minor);
625         cdev_init(&fw_mgmt->cdev, &fw_mgmt_fops);
626
627         ret = cdev_add(&fw_mgmt->cdev, fw_mgmt->dev_num, 1);
628         if (ret)
629                 goto err_remove_ida;
630
631         /* Add a soft link to the previously added char-dev within the bundle */
632         fw_mgmt->class_device = device_create(fw_mgmt_class, fw_mgmt->parent,
633                                               fw_mgmt->dev_num, NULL,
634                                               "gb-fw-mgmt-%d", minor);
635         if (IS_ERR(fw_mgmt->class_device)) {
636                 ret = PTR_ERR(fw_mgmt->class_device);
637                 goto err_del_cdev;
638         }
639
640         return 0;
641
642 err_del_cdev:
643         cdev_del(&fw_mgmt->cdev);
644 err_remove_ida:
645         ida_simple_remove(&fw_mgmt_minors_map, minor);
646 err_connection_disable:
647         gb_connection_disable(connection);
648 err_list_del:
649         mutex_lock(&list_mutex);
650         list_del(&fw_mgmt->node);
651         mutex_unlock(&list_mutex);
652
653         put_fw_mgmt(fw_mgmt);
654
655         return ret;
656 }
657
658 void gb_fw_mgmt_connection_exit(struct gb_connection *connection)
659 {
660         struct fw_mgmt *fw_mgmt;
661
662         if (!connection)
663                 return;
664
665         fw_mgmt = gb_connection_get_data(connection);
666
667         device_destroy(fw_mgmt_class, fw_mgmt->dev_num);
668         cdev_del(&fw_mgmt->cdev);
669         ida_simple_remove(&fw_mgmt_minors_map, MINOR(fw_mgmt->dev_num));
670
671         /*
672          * Disallow any new ioctl operations on the char device and wait for
673          * existing ones to finish.
674          */
675         mutex_lock(&fw_mgmt->mutex);
676         fw_mgmt->disabled = true;
677         mutex_unlock(&fw_mgmt->mutex);
678
679         /* All pending greybus operations should have finished by now */
680         gb_connection_disable(fw_mgmt->connection);
681
682         /* Disallow new users to get access to the fw_mgmt structure */
683         mutex_lock(&list_mutex);
684         list_del(&fw_mgmt->node);
685         mutex_unlock(&list_mutex);
686
687         /*
688          * All current users of fw_mgmt would have taken a reference to it by
689          * now, we can drop our reference and wait the last user will get
690          * fw_mgmt freed.
691          */
692         put_fw_mgmt(fw_mgmt);
693 }
694
695 int fw_mgmt_init(void)
696 {
697         int ret;
698
699         fw_mgmt_class = class_create(THIS_MODULE, "gb_fw_mgmt");
700         if (IS_ERR(fw_mgmt_class))
701                 return PTR_ERR(fw_mgmt_class);
702
703         ret = alloc_chrdev_region(&fw_mgmt_dev_num, 0, NUM_MINORS,
704                                   "gb_fw_mgmt");
705         if (ret)
706                 goto err_remove_class;
707
708         return 0;
709
710 err_remove_class:
711         class_destroy(fw_mgmt_class);
712         return ret;
713 }
714
715 void fw_mgmt_exit(void)
716 {
717         unregister_chrdev_region(fw_mgmt_dev_num, NUM_MINORS);
718         class_destroy(fw_mgmt_class);
719         ida_destroy(&fw_mgmt_minors_map);
720 }