Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc5 721 lines 19 kB view raw
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 24struct 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 59static struct class *fw_mgmt_class; 60static dev_t fw_mgmt_dev_num; 61static DEFINE_IDA(fw_mgmt_minors_map); 62static LIST_HEAD(fw_mgmt_list); 63static DEFINE_MUTEX(list_mutex); 64 65static 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 */ 78static 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 */ 84static 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 99unlock: 100 mutex_unlock(&list_mutex); 101 102 return fw_mgmt; 103} 104 105static 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 140static 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 193static 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 243static 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 299static 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 343static 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 387static 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 400static 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 408static 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 533static 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 565static 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 572int 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 588int 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 643err_del_cdev: 644 cdev_del(&fw_mgmt->cdev); 645err_remove_ida: 646 ida_simple_remove(&fw_mgmt_minors_map, minor); 647err_connection_disable: 648 gb_connection_disable(connection); 649err_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 659void 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 696int 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 711err_remove_class: 712 class_destroy(fw_mgmt_class); 713 return ret; 714} 715 716void 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}