root/drivers/staging/greybus/fw-management.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fw_mgmt_kref_release
  2. put_fw_mgmt
  3. get_fw_mgmt
  4. fw_mgmt_interface_fw_version_operation
  5. fw_mgmt_load_and_validate_operation
  6. fw_mgmt_interface_fw_loaded_operation
  7. fw_mgmt_backend_fw_version_operation
  8. fw_mgmt_backend_fw_update_operation
  9. fw_mgmt_backend_fw_updated_operation
  10. fw_mgmt_open
  11. fw_mgmt_release
  12. fw_mgmt_ioctl
  13. fw_mgmt_ioctl_unlocked
  14. gb_fw_mgmt_request_handler
  15. gb_fw_mgmt_connection_init
  16. gb_fw_mgmt_connection_exit
  17. fw_mgmt_init
  18. fw_mgmt_exit

   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 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 
  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  */
  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 */
  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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 }

/* [<][>][^][v][top][bottom][index][help] */