Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus Firmware Management Protocol Driver.
0004  *
0005  * Copyright 2016 Google Inc.
0006  * Copyright 2016 Linaro Ltd.
0007  */
0008 
0009 #include <linux/cdev.h>
0010 #include <linux/completion.h>
0011 #include <linux/firmware.h>
0012 #include <linux/fs.h>
0013 #include <linux/idr.h>
0014 #include <linux/ioctl.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/greybus.h>
0017 
0018 #include "firmware.h"
0019 #include "greybus_firmware.h"
0020 
0021 #define FW_MGMT_TIMEOUT_MS      1000
0022 
0023 struct fw_mgmt {
0024     struct device       *parent;
0025     struct gb_connection    *connection;
0026     struct kref     kref;
0027     struct list_head    node;
0028 
0029     /* Common id-map for interface and backend firmware requests */
0030     struct ida      id_map;
0031     struct mutex        mutex;
0032     struct completion   completion;
0033     struct cdev     cdev;
0034     struct device       *class_device;
0035     dev_t           dev_num;
0036     unsigned int        timeout_jiffies;
0037     bool            disabled; /* connection getting disabled */
0038 
0039     /* Interface Firmware specific fields */
0040     bool            mode_switch_started;
0041     bool            intf_fw_loaded;
0042     u8          intf_fw_request_id;
0043     u8          intf_fw_status;
0044     u16         intf_fw_major;
0045     u16         intf_fw_minor;
0046 
0047     /* Backend Firmware specific fields */
0048     u8          backend_fw_request_id;
0049     u8          backend_fw_status;
0050 };
0051 
0052 /*
0053  * Number of minor devices this driver supports.
0054  * There will be exactly one required per Interface.
0055  */
0056 #define NUM_MINORS      U8_MAX
0057 
0058 static struct class *fw_mgmt_class;
0059 static dev_t fw_mgmt_dev_num;
0060 static DEFINE_IDA(fw_mgmt_minors_map);
0061 static LIST_HEAD(fw_mgmt_list);
0062 static DEFINE_MUTEX(list_mutex);
0063 
0064 static void fw_mgmt_kref_release(struct kref *kref)
0065 {
0066     struct fw_mgmt *fw_mgmt = container_of(kref, struct fw_mgmt, kref);
0067 
0068     ida_destroy(&fw_mgmt->id_map);
0069     kfree(fw_mgmt);
0070 }
0071 
0072 /*
0073  * All users of fw_mgmt take a reference (from within list_mutex lock), before
0074  * they get a pointer to play with. And the structure will be freed only after
0075  * the last user has put the reference to it.
0076  */
0077 static void put_fw_mgmt(struct fw_mgmt *fw_mgmt)
0078 {
0079     kref_put(&fw_mgmt->kref, fw_mgmt_kref_release);
0080 }
0081 
0082 /* Caller must call put_fw_mgmt() after using struct fw_mgmt */
0083 static struct fw_mgmt *get_fw_mgmt(struct cdev *cdev)
0084 {
0085     struct fw_mgmt *fw_mgmt;
0086 
0087     mutex_lock(&list_mutex);
0088 
0089     list_for_each_entry(fw_mgmt, &fw_mgmt_list, node) {
0090         if (&fw_mgmt->cdev == cdev) {
0091             kref_get(&fw_mgmt->kref);
0092             goto unlock;
0093         }
0094     }
0095 
0096     fw_mgmt = NULL;
0097 
0098 unlock:
0099     mutex_unlock(&list_mutex);
0100 
0101     return fw_mgmt;
0102 }
0103 
0104 static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt,
0105                           struct fw_mgmt_ioc_get_intf_version *fw_info)
0106 {
0107     struct gb_connection *connection = fw_mgmt->connection;
0108     struct gb_fw_mgmt_interface_fw_version_response response;
0109     int ret;
0110 
0111     ret = gb_operation_sync(connection,
0112                 GB_FW_MGMT_TYPE_INTERFACE_FW_VERSION, NULL, 0,
0113                 &response, sizeof(response));
0114     if (ret) {
0115         dev_err(fw_mgmt->parent,
0116             "failed to get interface firmware version (%d)\n", ret);
0117         return ret;
0118     }
0119 
0120     fw_info->major = le16_to_cpu(response.major);
0121     fw_info->minor = le16_to_cpu(response.minor);
0122 
0123     strncpy(fw_info->firmware_tag, response.firmware_tag,
0124         GB_FIRMWARE_TAG_MAX_SIZE);
0125 
0126     /*
0127      * The firmware-tag should be NULL terminated, otherwise throw error but
0128      * don't fail.
0129      */
0130     if (fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
0131         dev_err(fw_mgmt->parent,
0132             "fw-version: firmware-tag is not NULL terminated\n");
0133         fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] = '\0';
0134     }
0135 
0136     return 0;
0137 }
0138 
0139 static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
0140                            u8 load_method, const char *tag)
0141 {
0142     struct gb_fw_mgmt_load_and_validate_fw_request request;
0143     int ret;
0144 
0145     if (load_method != GB_FW_LOAD_METHOD_UNIPRO &&
0146         load_method != GB_FW_LOAD_METHOD_INTERNAL) {
0147         dev_err(fw_mgmt->parent,
0148             "invalid load-method (%d)\n", load_method);
0149         return -EINVAL;
0150     }
0151 
0152     request.load_method = load_method;
0153     strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
0154 
0155     /*
0156      * The firmware-tag should be NULL terminated, otherwise throw error and
0157      * fail.
0158      */
0159     if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
0160         dev_err(fw_mgmt->parent, "load-and-validate: firmware-tag is not NULL terminated\n");
0161         return -EINVAL;
0162     }
0163 
0164     /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
0165     ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
0166     if (ret < 0) {
0167         dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
0168             ret);
0169         return ret;
0170     }
0171 
0172     fw_mgmt->intf_fw_request_id = ret;
0173     fw_mgmt->intf_fw_loaded = false;
0174     request.request_id = ret;
0175 
0176     ret = gb_operation_sync(fw_mgmt->connection,
0177                 GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW, &request,
0178                 sizeof(request), NULL, 0);
0179     if (ret) {
0180         ida_simple_remove(&fw_mgmt->id_map,
0181                   fw_mgmt->intf_fw_request_id);
0182         fw_mgmt->intf_fw_request_id = 0;
0183         dev_err(fw_mgmt->parent,
0184             "load and validate firmware request failed (%d)\n",
0185             ret);
0186         return ret;
0187     }
0188 
0189     return 0;
0190 }
0191 
0192 static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op)
0193 {
0194     struct gb_connection *connection = op->connection;
0195     struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
0196     struct gb_fw_mgmt_loaded_fw_request *request;
0197 
0198     /* No pending load and validate request ? */
0199     if (!fw_mgmt->intf_fw_request_id) {
0200         dev_err(fw_mgmt->parent,
0201             "unexpected firmware loaded request received\n");
0202         return -ENODEV;
0203     }
0204 
0205     if (op->request->payload_size != sizeof(*request)) {
0206         dev_err(fw_mgmt->parent, "illegal size of firmware loaded request (%zu != %zu)\n",
0207             op->request->payload_size, sizeof(*request));
0208         return -EINVAL;
0209     }
0210 
0211     request = op->request->payload;
0212 
0213     /* Invalid request-id ? */
0214     if (request->request_id != fw_mgmt->intf_fw_request_id) {
0215         dev_err(fw_mgmt->parent, "invalid request id for firmware loaded request (%02u != %02u)\n",
0216             fw_mgmt->intf_fw_request_id, request->request_id);
0217         return -ENODEV;
0218     }
0219 
0220     ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
0221     fw_mgmt->intf_fw_request_id = 0;
0222     fw_mgmt->intf_fw_status = request->status;
0223     fw_mgmt->intf_fw_major = le16_to_cpu(request->major);
0224     fw_mgmt->intf_fw_minor = le16_to_cpu(request->minor);
0225 
0226     if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_FAILED)
0227         dev_err(fw_mgmt->parent,
0228             "failed to load interface firmware, status:%02x\n",
0229             fw_mgmt->intf_fw_status);
0230     else if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_VALIDATION_FAILED)
0231         dev_err(fw_mgmt->parent,
0232             "failed to validate interface firmware, status:%02x\n",
0233             fw_mgmt->intf_fw_status);
0234     else
0235         fw_mgmt->intf_fw_loaded = true;
0236 
0237     complete(&fw_mgmt->completion);
0238 
0239     return 0;
0240 }
0241 
0242 static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt,
0243                         struct fw_mgmt_ioc_get_backend_version *fw_info)
0244 {
0245     struct gb_connection *connection = fw_mgmt->connection;
0246     struct gb_fw_mgmt_backend_fw_version_request request;
0247     struct gb_fw_mgmt_backend_fw_version_response response;
0248     int ret;
0249 
0250     strncpy(request.firmware_tag, fw_info->firmware_tag,
0251         GB_FIRMWARE_TAG_MAX_SIZE);
0252 
0253     /*
0254      * The firmware-tag should be NULL terminated, otherwise throw error and
0255      * fail.
0256      */
0257     if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
0258         dev_err(fw_mgmt->parent, "backend-version: firmware-tag is not NULL terminated\n");
0259         return -EINVAL;
0260     }
0261 
0262     ret = gb_operation_sync(connection,
0263                 GB_FW_MGMT_TYPE_BACKEND_FW_VERSION, &request,
0264                 sizeof(request), &response, sizeof(response));
0265     if (ret) {
0266         dev_err(fw_mgmt->parent, "failed to get version of %s backend firmware (%d)\n",
0267             fw_info->firmware_tag, ret);
0268         return ret;
0269     }
0270 
0271     fw_info->status = response.status;
0272 
0273     /* Reset version as that should be non-zero only for success case */
0274     fw_info->major = 0;
0275     fw_info->minor = 0;
0276 
0277     switch (fw_info->status) {
0278     case GB_FW_BACKEND_VERSION_STATUS_SUCCESS:
0279         fw_info->major = le16_to_cpu(response.major);
0280         fw_info->minor = le16_to_cpu(response.minor);
0281         break;
0282     case GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE:
0283     case GB_FW_BACKEND_VERSION_STATUS_RETRY:
0284         break;
0285     case GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED:
0286         dev_err(fw_mgmt->parent,
0287             "Firmware with tag %s is not supported by Interface\n",
0288             fw_info->firmware_tag);
0289         break;
0290     default:
0291         dev_err(fw_mgmt->parent, "Invalid status received: %u\n",
0292             fw_info->status);
0293     }
0294 
0295     return 0;
0296 }
0297 
0298 static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
0299                            char *tag)
0300 {
0301     struct gb_fw_mgmt_backend_fw_update_request request;
0302     int ret;
0303 
0304     strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
0305 
0306     /*
0307      * The firmware-tag should be NULL terminated, otherwise throw error and
0308      * fail.
0309      */
0310     if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
0311         dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n");
0312         return -EINVAL;
0313     }
0314 
0315     /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
0316     ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
0317     if (ret < 0) {
0318         dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
0319             ret);
0320         return ret;
0321     }
0322 
0323     fw_mgmt->backend_fw_request_id = ret;
0324     request.request_id = ret;
0325 
0326     ret = gb_operation_sync(fw_mgmt->connection,
0327                 GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE, &request,
0328                 sizeof(request), NULL, 0);
0329     if (ret) {
0330         ida_simple_remove(&fw_mgmt->id_map,
0331                   fw_mgmt->backend_fw_request_id);
0332         fw_mgmt->backend_fw_request_id = 0;
0333         dev_err(fw_mgmt->parent,
0334             "backend %s firmware update request failed (%d)\n", tag,
0335             ret);
0336         return ret;
0337     }
0338 
0339     return 0;
0340 }
0341 
0342 static int fw_mgmt_backend_fw_updated_operation(struct gb_operation *op)
0343 {
0344     struct gb_connection *connection = op->connection;
0345     struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
0346     struct gb_fw_mgmt_backend_fw_updated_request *request;
0347 
0348     /* No pending load and validate request ? */
0349     if (!fw_mgmt->backend_fw_request_id) {
0350         dev_err(fw_mgmt->parent, "unexpected backend firmware updated request received\n");
0351         return -ENODEV;
0352     }
0353 
0354     if (op->request->payload_size != sizeof(*request)) {
0355         dev_err(fw_mgmt->parent, "illegal size of backend firmware updated request (%zu != %zu)\n",
0356             op->request->payload_size, sizeof(*request));
0357         return -EINVAL;
0358     }
0359 
0360     request = op->request->payload;
0361 
0362     /* Invalid request-id ? */
0363     if (request->request_id != fw_mgmt->backend_fw_request_id) {
0364         dev_err(fw_mgmt->parent, "invalid request id for backend firmware updated request (%02u != %02u)\n",
0365             fw_mgmt->backend_fw_request_id, request->request_id);
0366         return -ENODEV;
0367     }
0368 
0369     ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
0370     fw_mgmt->backend_fw_request_id = 0;
0371     fw_mgmt->backend_fw_status = request->status;
0372 
0373     if ((fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_SUCCESS) &&
0374         (fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_RETRY))
0375         dev_err(fw_mgmt->parent,
0376             "failed to load backend firmware: %02x\n",
0377             fw_mgmt->backend_fw_status);
0378 
0379     complete(&fw_mgmt->completion);
0380 
0381     return 0;
0382 }
0383 
0384 /* Char device fops */
0385 
0386 static int fw_mgmt_open(struct inode *inode, struct file *file)
0387 {
0388     struct fw_mgmt *fw_mgmt = get_fw_mgmt(inode->i_cdev);
0389 
0390     /* fw_mgmt structure can't get freed until file descriptor is closed */
0391     if (fw_mgmt) {
0392         file->private_data = fw_mgmt;
0393         return 0;
0394     }
0395 
0396     return -ENODEV;
0397 }
0398 
0399 static int fw_mgmt_release(struct inode *inode, struct file *file)
0400 {
0401     struct fw_mgmt *fw_mgmt = file->private_data;
0402 
0403     put_fw_mgmt(fw_mgmt);
0404     return 0;
0405 }
0406 
0407 static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd,
0408              void __user *buf)
0409 {
0410     struct fw_mgmt_ioc_get_intf_version intf_fw_info;
0411     struct fw_mgmt_ioc_get_backend_version backend_fw_info;
0412     struct fw_mgmt_ioc_intf_load_and_validate intf_load;
0413     struct fw_mgmt_ioc_backend_fw_update backend_update;
0414     unsigned int timeout;
0415     int ret;
0416 
0417     /* Reject any operations after mode-switch has started */
0418     if (fw_mgmt->mode_switch_started)
0419         return -EBUSY;
0420 
0421     switch (cmd) {
0422     case FW_MGMT_IOC_GET_INTF_FW:
0423         ret = fw_mgmt_interface_fw_version_operation(fw_mgmt,
0424                                  &intf_fw_info);
0425         if (ret)
0426             return ret;
0427 
0428         if (copy_to_user(buf, &intf_fw_info, sizeof(intf_fw_info)))
0429             return -EFAULT;
0430 
0431         return 0;
0432     case FW_MGMT_IOC_GET_BACKEND_FW:
0433         if (copy_from_user(&backend_fw_info, buf,
0434                    sizeof(backend_fw_info)))
0435             return -EFAULT;
0436 
0437         ret = fw_mgmt_backend_fw_version_operation(fw_mgmt,
0438                                &backend_fw_info);
0439         if (ret)
0440             return ret;
0441 
0442         if (copy_to_user(buf, &backend_fw_info,
0443                  sizeof(backend_fw_info)))
0444             return -EFAULT;
0445 
0446         return 0;
0447     case FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE:
0448         if (copy_from_user(&intf_load, buf, sizeof(intf_load)))
0449             return -EFAULT;
0450 
0451         ret = fw_mgmt_load_and_validate_operation(fw_mgmt,
0452                 intf_load.load_method, intf_load.firmware_tag);
0453         if (ret)
0454             return ret;
0455 
0456         if (!wait_for_completion_timeout(&fw_mgmt->completion,
0457                          fw_mgmt->timeout_jiffies)) {
0458             dev_err(fw_mgmt->parent, "timed out waiting for firmware load and validation to finish\n");
0459             return -ETIMEDOUT;
0460         }
0461 
0462         intf_load.status = fw_mgmt->intf_fw_status;
0463         intf_load.major = fw_mgmt->intf_fw_major;
0464         intf_load.minor = fw_mgmt->intf_fw_minor;
0465 
0466         if (copy_to_user(buf, &intf_load, sizeof(intf_load)))
0467             return -EFAULT;
0468 
0469         return 0;
0470     case FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE:
0471         if (copy_from_user(&backend_update, buf,
0472                    sizeof(backend_update)))
0473             return -EFAULT;
0474 
0475         ret = fw_mgmt_backend_fw_update_operation(fw_mgmt,
0476                               backend_update.firmware_tag);
0477         if (ret)
0478             return ret;
0479 
0480         if (!wait_for_completion_timeout(&fw_mgmt->completion,
0481                          fw_mgmt->timeout_jiffies)) {
0482             dev_err(fw_mgmt->parent, "timed out waiting for backend firmware update to finish\n");
0483             return -ETIMEDOUT;
0484         }
0485 
0486         backend_update.status = fw_mgmt->backend_fw_status;
0487 
0488         if (copy_to_user(buf, &backend_update, sizeof(backend_update)))
0489             return -EFAULT;
0490 
0491         return 0;
0492     case FW_MGMT_IOC_SET_TIMEOUT_MS:
0493         if (get_user(timeout, (unsigned int __user *)buf))
0494             return -EFAULT;
0495 
0496         if (!timeout) {
0497             dev_err(fw_mgmt->parent, "timeout can't be zero\n");
0498             return -EINVAL;
0499         }
0500 
0501         fw_mgmt->timeout_jiffies = msecs_to_jiffies(timeout);
0502 
0503         return 0;
0504     case FW_MGMT_IOC_MODE_SWITCH:
0505         if (!fw_mgmt->intf_fw_loaded) {
0506             dev_err(fw_mgmt->parent,
0507                 "Firmware not loaded for mode-switch\n");
0508             return -EPERM;
0509         }
0510 
0511         /*
0512          * Disallow new ioctls as the fw-core bundle driver is going to
0513          * get disconnected soon and the character device will get
0514          * removed.
0515          */
0516         fw_mgmt->mode_switch_started = true;
0517 
0518         ret = gb_interface_request_mode_switch(fw_mgmt->connection->intf);
0519         if (ret) {
0520             dev_err(fw_mgmt->parent, "Mode-switch failed: %d\n",
0521                 ret);
0522             fw_mgmt->mode_switch_started = false;
0523             return ret;
0524         }
0525 
0526         return 0;
0527     default:
0528         return -ENOTTY;
0529     }
0530 }
0531 
0532 static long fw_mgmt_ioctl_unlocked(struct file *file, unsigned int cmd,
0533                    unsigned long arg)
0534 {
0535     struct fw_mgmt *fw_mgmt = file->private_data;
0536     struct gb_bundle *bundle = fw_mgmt->connection->bundle;
0537     int ret = -ENODEV;
0538 
0539     /*
0540      * Serialize ioctls.
0541      *
0542      * We don't want the user to do few operations in parallel. For example,
0543      * updating Interface firmware in parallel for the same Interface. There
0544      * is no need to do things in parallel for speed and we can avoid having
0545      * complicated code for now.
0546      *
0547      * This is also used to protect ->disabled, which is used to check if
0548      * the connection is getting disconnected, so that we don't start any
0549      * new operations.
0550      */
0551     mutex_lock(&fw_mgmt->mutex);
0552     if (!fw_mgmt->disabled) {
0553         ret = gb_pm_runtime_get_sync(bundle);
0554         if (!ret) {
0555             ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg);
0556             gb_pm_runtime_put_autosuspend(bundle);
0557         }
0558     }
0559     mutex_unlock(&fw_mgmt->mutex);
0560 
0561     return ret;
0562 }
0563 
0564 static const struct file_operations fw_mgmt_fops = {
0565     .owner      = THIS_MODULE,
0566     .open       = fw_mgmt_open,
0567     .release    = fw_mgmt_release,
0568     .unlocked_ioctl = fw_mgmt_ioctl_unlocked,
0569 };
0570 
0571 int gb_fw_mgmt_request_handler(struct gb_operation *op)
0572 {
0573     u8 type = op->type;
0574 
0575     switch (type) {
0576     case GB_FW_MGMT_TYPE_LOADED_FW:
0577         return fw_mgmt_interface_fw_loaded_operation(op);
0578     case GB_FW_MGMT_TYPE_BACKEND_FW_UPDATED:
0579         return fw_mgmt_backend_fw_updated_operation(op);
0580     default:
0581         dev_err(&op->connection->bundle->dev,
0582             "unsupported request: %u\n", type);
0583         return -EINVAL;
0584     }
0585 }
0586 
0587 int gb_fw_mgmt_connection_init(struct gb_connection *connection)
0588 {
0589     struct fw_mgmt *fw_mgmt;
0590     int ret, minor;
0591 
0592     if (!connection)
0593         return 0;
0594 
0595     fw_mgmt = kzalloc(sizeof(*fw_mgmt), GFP_KERNEL);
0596     if (!fw_mgmt)
0597         return -ENOMEM;
0598 
0599     fw_mgmt->parent = &connection->bundle->dev;
0600     fw_mgmt->timeout_jiffies = msecs_to_jiffies(FW_MGMT_TIMEOUT_MS);
0601     fw_mgmt->connection = connection;
0602 
0603     gb_connection_set_data(connection, fw_mgmt);
0604     init_completion(&fw_mgmt->completion);
0605     ida_init(&fw_mgmt->id_map);
0606     mutex_init(&fw_mgmt->mutex);
0607     kref_init(&fw_mgmt->kref);
0608 
0609     mutex_lock(&list_mutex);
0610     list_add(&fw_mgmt->node, &fw_mgmt_list);
0611     mutex_unlock(&list_mutex);
0612 
0613     ret = gb_connection_enable(connection);
0614     if (ret)
0615         goto err_list_del;
0616 
0617     minor = ida_simple_get(&fw_mgmt_minors_map, 0, NUM_MINORS, GFP_KERNEL);
0618     if (minor < 0) {
0619         ret = minor;
0620         goto err_connection_disable;
0621     }
0622 
0623     /* Add a char device to allow userspace to interact with fw-mgmt */
0624     fw_mgmt->dev_num = MKDEV(MAJOR(fw_mgmt_dev_num), minor);
0625     cdev_init(&fw_mgmt->cdev, &fw_mgmt_fops);
0626 
0627     ret = cdev_add(&fw_mgmt->cdev, fw_mgmt->dev_num, 1);
0628     if (ret)
0629         goto err_remove_ida;
0630 
0631     /* Add a soft link to the previously added char-dev within the bundle */
0632     fw_mgmt->class_device = device_create(fw_mgmt_class, fw_mgmt->parent,
0633                           fw_mgmt->dev_num, NULL,
0634                           "gb-fw-mgmt-%d", minor);
0635     if (IS_ERR(fw_mgmt->class_device)) {
0636         ret = PTR_ERR(fw_mgmt->class_device);
0637         goto err_del_cdev;
0638     }
0639 
0640     return 0;
0641 
0642 err_del_cdev:
0643     cdev_del(&fw_mgmt->cdev);
0644 err_remove_ida:
0645     ida_simple_remove(&fw_mgmt_minors_map, minor);
0646 err_connection_disable:
0647     gb_connection_disable(connection);
0648 err_list_del:
0649     mutex_lock(&list_mutex);
0650     list_del(&fw_mgmt->node);
0651     mutex_unlock(&list_mutex);
0652 
0653     put_fw_mgmt(fw_mgmt);
0654 
0655     return ret;
0656 }
0657 
0658 void gb_fw_mgmt_connection_exit(struct gb_connection *connection)
0659 {
0660     struct fw_mgmt *fw_mgmt;
0661 
0662     if (!connection)
0663         return;
0664 
0665     fw_mgmt = gb_connection_get_data(connection);
0666 
0667     device_destroy(fw_mgmt_class, fw_mgmt->dev_num);
0668     cdev_del(&fw_mgmt->cdev);
0669     ida_simple_remove(&fw_mgmt_minors_map, MINOR(fw_mgmt->dev_num));
0670 
0671     /*
0672      * Disallow any new ioctl operations on the char device and wait for
0673      * existing ones to finish.
0674      */
0675     mutex_lock(&fw_mgmt->mutex);
0676     fw_mgmt->disabled = true;
0677     mutex_unlock(&fw_mgmt->mutex);
0678 
0679     /* All pending greybus operations should have finished by now */
0680     gb_connection_disable(fw_mgmt->connection);
0681 
0682     /* Disallow new users to get access to the fw_mgmt structure */
0683     mutex_lock(&list_mutex);
0684     list_del(&fw_mgmt->node);
0685     mutex_unlock(&list_mutex);
0686 
0687     /*
0688      * All current users of fw_mgmt would have taken a reference to it by
0689      * now, we can drop our reference and wait the last user will get
0690      * fw_mgmt freed.
0691      */
0692     put_fw_mgmt(fw_mgmt);
0693 }
0694 
0695 int fw_mgmt_init(void)
0696 {
0697     int ret;
0698 
0699     fw_mgmt_class = class_create(THIS_MODULE, "gb_fw_mgmt");
0700     if (IS_ERR(fw_mgmt_class))
0701         return PTR_ERR(fw_mgmt_class);
0702 
0703     ret = alloc_chrdev_region(&fw_mgmt_dev_num, 0, NUM_MINORS,
0704                   "gb_fw_mgmt");
0705     if (ret)
0706         goto err_remove_class;
0707 
0708     return 0;
0709 
0710 err_remove_class:
0711     class_destroy(fw_mgmt_class);
0712     return ret;
0713 }
0714 
0715 void fw_mgmt_exit(void)
0716 {
0717     unregister_chrdev_region(fw_mgmt_dev_num, NUM_MINORS);
0718     class_destroy(fw_mgmt_class);
0719     ida_destroy(&fw_mgmt_minors_map);
0720 }