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