fw-management.c (19080B)
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 23struct 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 58static struct class *fw_mgmt_class; 59static dev_t fw_mgmt_dev_num; 60static DEFINE_IDA(fw_mgmt_minors_map); 61static LIST_HEAD(fw_mgmt_list); 62static DEFINE_MUTEX(list_mutex); 63 64static 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 */ 77static 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 */ 83static 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 98unlock: 99 mutex_unlock(&list_mutex); 100 101 return fw_mgmt; 102} 103 104static 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 139static 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 192static 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 242static 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 298static 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 342static 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 386static 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 399static 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 407static 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 532static 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 564static 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 571int 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 587int 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 642err_del_cdev: 643 cdev_del(&fw_mgmt->cdev); 644err_remove_ida: 645 ida_simple_remove(&fw_mgmt_minors_map, minor); 646err_connection_disable: 647 gb_connection_disable(connection); 648err_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 658void 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 695int 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 710err_remove_class: 711 class_destroy(fw_mgmt_class); 712 return ret; 713} 714 715void 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}