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