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