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
fw_mgmt_kref_release(struct kref * kref)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 */
put_fw_mgmt(struct fw_mgmt * fw_mgmt)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 */
get_fw_mgmt(struct cdev * cdev)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
fw_mgmt_interface_fw_version_operation(struct fw_mgmt * fw_mgmt,struct fw_mgmt_ioc_get_intf_version * fw_info)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
fw_mgmt_load_and_validate_operation(struct fw_mgmt * fw_mgmt,u8 load_method,const char * tag)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
fw_mgmt_interface_fw_loaded_operation(struct gb_operation * op)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
fw_mgmt_backend_fw_version_operation(struct fw_mgmt * fw_mgmt,struct fw_mgmt_ioc_get_backend_version * fw_info)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
fw_mgmt_backend_fw_update_operation(struct fw_mgmt * fw_mgmt,char * tag)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
fw_mgmt_backend_fw_updated_operation(struct gb_operation * op)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
fw_mgmt_open(struct inode * inode,struct file * file)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
fw_mgmt_release(struct inode * inode,struct file * file)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
fw_mgmt_ioctl(struct fw_mgmt * fw_mgmt,unsigned int cmd,void __user * buf)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
fw_mgmt_ioctl_unlocked(struct file * file,unsigned int cmd,unsigned long arg)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
gb_fw_mgmt_request_handler(struct gb_operation * op)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
gb_fw_mgmt_connection_init(struct gb_connection * connection)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
gb_fw_mgmt_connection_exit(struct gb_connection * connection)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
fw_mgmt_init(void)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
fw_mgmt_exit(void)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 }
721