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

bus: fsl-mc: add fsl-mc userspace support

Adding userspace support for the MC (Management Complex) means exporting
an ioctl capable device file representing the root resource container.

This new functionality in the fsl-mc bus driver intends to provide
userspace applications an interface to interact with the MC firmware.

Commands that are composed in userspace are sent to the MC firmware
through the FSL_MC_SEND_MC_COMMAND ioctl. By default the implicit MC
I/O portal is used for this operation, but if the implicit one is busy,
a dynamic portal is allocated and then freed upon execution.

The command received through the ioctl interface is checked against a
known whitelist of accepted MC commands. Commands that attempt a change
in hardware configuration will need CAP_NET_ADMIN, while commands used
in debugging do not need it.

Acked-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Link: https://lore.kernel.org/r/20210114170752.2927915-4-ciorneiioana@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ioana Ciornei and committed by
Greg Kroah-Hartman
2cf1e703 46707989

+618
+1
Documentation/userspace-api/ioctl/ioctl-number.rst
··· 180 180 'R' 00-1F linux/random.h conflict! 181 181 'R' 01 linux/rfkill.h conflict! 182 182 'R' C0-DF net/bluetooth/rfcomm.h 183 + 'R' E0 uapi/linux/fsl_mc.h 183 184 'S' all linux/cdrom.h conflict! 184 185 'S' 80-81 scsi/scsi_ioctl.h conflict! 185 186 'S' 82-FF scsi/scsi.h conflict!
+7
drivers/bus/fsl-mc/Kconfig
··· 14 14 architecture. The fsl-mc bus driver handles discovery of 15 15 DPAA2 objects (which are represented as Linux devices) and 16 16 binding objects to drivers. 17 + 18 + config FSL_MC_UAPI_SUPPORT 19 + bool "Management Complex (MC) userspace support" 20 + depends on FSL_MC_BUS 21 + help 22 + Provides userspace support for interrogating, creating, destroying or 23 + configuring DPAA2 objects exported by the Management Complex.
+3
drivers/bus/fsl-mc/Makefile
··· 16 16 fsl-mc-allocator.o \ 17 17 fsl-mc-msi.o \ 18 18 dpmcp.o 19 + 20 + # MC userspace support 21 + obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
+12
drivers/bus/fsl-mc/dprc-driver.c
··· 603 603 struct irq_domain *mc_msi_domain; 604 604 bool mc_io_created = false; 605 605 bool msi_domain_set = false; 606 + bool uapi_created = false; 606 607 u16 major_ver, minor_ver; 607 608 size_t region_size; 608 609 int error; ··· 636 635 return error; 637 636 638 637 mc_io_created = true; 638 + } else { 639 + error = fsl_mc_uapi_create_device_file(mc_bus); 640 + if (error < 0) 641 + return -EPROBE_DEFER; 642 + uapi_created = true; 639 643 } 640 644 641 645 mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev); ··· 697 691 fsl_destroy_mc_io(mc_dev->mc_io); 698 692 mc_dev->mc_io = NULL; 699 693 } 694 + 695 + if (uapi_created) 696 + fsl_mc_uapi_remove_device_file(mc_bus); 700 697 701 698 return error; 702 699 } ··· 772 763 773 764 int dprc_cleanup(struct fsl_mc_device *mc_dev) 774 765 { 766 + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 775 767 int error; 776 768 777 769 /* this function should be called only for DPRCs, it ··· 803 793 if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { 804 794 fsl_destroy_mc_io(mc_dev->mc_io); 805 795 mc_dev->mc_io = NULL; 796 + } else { 797 + fsl_mc_uapi_remove_device_file(mc_bus); 806 798 } 807 799 808 800 return 0;
+39
drivers/bus/fsl-mc/fsl-mc-private.h
··· 10 10 11 11 #include <linux/fsl/mc.h> 12 12 #include <linux/mutex.h> 13 + #include <linux/ioctl.h> 14 + #include <linux/miscdevice.h> 13 15 14 16 /* 15 17 * Data Path Management Complex (DPMNG) General API ··· 545 543 }; 546 544 547 545 /** 546 + * struct fsl_mc_uapi - information associated with a device file 547 + * @misc: struct miscdevice linked to the root dprc 548 + * @device: newly created device in /dev 549 + * @mutex: mutex lock to serialize the open/release operations 550 + * @local_instance_in_use: local MC I/O instance in use or not 551 + * @static_mc_io: pointer to the static MC I/O object 552 + */ 553 + struct fsl_mc_uapi { 554 + struct miscdevice misc; 555 + struct device *device; 556 + struct mutex mutex; /* serialize open/release operations */ 557 + u32 local_instance_in_use; 558 + struct fsl_mc_io *static_mc_io; 559 + }; 560 + 561 + /** 548 562 * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC 549 563 * @mc_dev: fsl-mc device for the bus device itself. 550 564 * @resource_pools: array of resource pools (one pool per resource type) ··· 569 551 * @irq_resources: Pointer to array of IRQ objects for the IRQ pool 570 552 * @scan_mutex: Serializes bus scanning 571 553 * @dprc_attr: DPRC attributes 554 + * @uapi_misc: struct that abstracts the interaction with userspace 572 555 */ 573 556 struct fsl_mc_bus { 574 557 struct fsl_mc_device mc_dev; ··· 577 558 struct fsl_mc_device_irq *irq_resources; 578 559 struct mutex scan_mutex; /* serializes bus scanning */ 579 560 struct dprc_attributes dprc_attr; 561 + struct fsl_mc_uapi uapi_misc; 580 562 }; 581 563 582 564 #define to_fsl_mc_bus(_mc_dev) \ ··· 633 613 struct fsl_mc_device *mc_bus_dev); 634 614 635 615 u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd); 616 + 617 + #ifdef CONFIG_FSL_MC_UAPI_SUPPORT 618 + 619 + int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus); 620 + 621 + void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus); 622 + 623 + #else 624 + 625 + static inline int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus) 626 + { 627 + return 0; 628 + } 629 + 630 + static inline void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus) 631 + { 632 + } 633 + 634 + #endif 636 635 637 636 #endif /* _FSL_MC_PRIVATE_H_ */
+547
drivers/bus/fsl-mc/fsl-mc-uapi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Management Complex (MC) userspace support 4 + * 5 + * Copyright 2021 NXP 6 + * 7 + */ 8 + 9 + #include <linux/slab.h> 10 + #include <linux/fs.h> 11 + #include <linux/uaccess.h> 12 + #include <linux/miscdevice.h> 13 + 14 + #include "fsl-mc-private.h" 15 + 16 + struct uapi_priv_data { 17 + struct fsl_mc_uapi *uapi; 18 + struct fsl_mc_io *mc_io; 19 + }; 20 + 21 + struct fsl_mc_cmd_desc { 22 + u16 cmdid_value; 23 + u16 cmdid_mask; 24 + int size; 25 + bool token; 26 + int flags; 27 + }; 28 + 29 + #define FSL_MC_CHECK_MODULE_ID BIT(0) 30 + #define FSL_MC_CAP_NET_ADMIN_NEEDED BIT(1) 31 + 32 + enum fsl_mc_cmd_index { 33 + DPDBG_DUMP = 0, 34 + DPDBG_SET, 35 + DPRC_GET_CONTAINER_ID, 36 + DPRC_CREATE_CONT, 37 + DPRC_DESTROY_CONT, 38 + DPRC_ASSIGN, 39 + DPRC_UNASSIGN, 40 + DPRC_GET_OBJ_COUNT, 41 + DPRC_GET_OBJ, 42 + DPRC_GET_RES_COUNT, 43 + DPRC_GET_RES_IDS, 44 + DPRC_SET_OBJ_LABEL, 45 + DPRC_SET_LOCKED, 46 + DPRC_CONNECT, 47 + DPRC_DISCONNECT, 48 + DPRC_GET_POOL, 49 + DPRC_GET_POOL_COUNT, 50 + DPRC_GET_CONNECTION, 51 + DPCI_GET_LINK_STATE, 52 + DPCI_GET_PEER_ATTR, 53 + DPAIOP_GET_SL_VERSION, 54 + DPAIOP_GET_STATE, 55 + DPMNG_GET_VERSION, 56 + DPSECI_GET_TX_QUEUE, 57 + DPMAC_GET_COUNTER, 58 + DPMAC_GET_MAC_ADDR, 59 + DPNI_SET_PRIM_MAC, 60 + DPNI_GET_PRIM_MAC, 61 + DPNI_GET_STATISTICS, 62 + DPNI_GET_LINK_STATE, 63 + GET_ATTR, 64 + GET_IRQ_MASK, 65 + GET_IRQ_STATUS, 66 + CLOSE, 67 + OPEN, 68 + GET_API_VERSION, 69 + DESTROY, 70 + CREATE, 71 + }; 72 + 73 + static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = { 74 + [DPDBG_DUMP] = { 75 + .cmdid_value = 0x1300, 76 + .cmdid_mask = 0xFFF0, 77 + .token = true, 78 + .size = 28, 79 + }, 80 + [DPDBG_SET] = { 81 + .cmdid_value = 0x1400, 82 + .cmdid_mask = 0xFFF0, 83 + .token = true, 84 + .size = 28, 85 + }, 86 + [DPRC_GET_CONTAINER_ID] = { 87 + .cmdid_value = 0x8300, 88 + .cmdid_mask = 0xFFF0, 89 + .token = false, 90 + .size = 8, 91 + }, 92 + [DPRC_CREATE_CONT] = { 93 + .cmdid_value = 0x1510, 94 + .cmdid_mask = 0xFFF0, 95 + .token = true, 96 + .size = 40, 97 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 98 + }, 99 + [DPRC_DESTROY_CONT] = { 100 + .cmdid_value = 0x1520, 101 + .cmdid_mask = 0xFFF0, 102 + .token = true, 103 + .size = 12, 104 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 105 + }, 106 + [DPRC_ASSIGN] = { 107 + .cmdid_value = 0x1570, 108 + .cmdid_mask = 0xFFF0, 109 + .token = true, 110 + .size = 40, 111 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 112 + }, 113 + [DPRC_UNASSIGN] = { 114 + .cmdid_value = 0x1580, 115 + .cmdid_mask = 0xFFF0, 116 + .token = true, 117 + .size = 40, 118 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 119 + }, 120 + [DPRC_GET_OBJ_COUNT] = { 121 + .cmdid_value = 0x1590, 122 + .cmdid_mask = 0xFFF0, 123 + .token = true, 124 + .size = 16, 125 + }, 126 + [DPRC_GET_OBJ] = { 127 + .cmdid_value = 0x15A0, 128 + .cmdid_mask = 0xFFF0, 129 + .token = true, 130 + .size = 12, 131 + }, 132 + [DPRC_GET_RES_COUNT] = { 133 + .cmdid_value = 0x15B0, 134 + .cmdid_mask = 0xFFF0, 135 + .token = true, 136 + .size = 32, 137 + }, 138 + [DPRC_GET_RES_IDS] = { 139 + .cmdid_value = 0x15C0, 140 + .cmdid_mask = 0xFFF0, 141 + .token = true, 142 + .size = 40, 143 + }, 144 + [DPRC_SET_OBJ_LABEL] = { 145 + .cmdid_value = 0x1610, 146 + .cmdid_mask = 0xFFF0, 147 + .token = true, 148 + .size = 48, 149 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 150 + }, 151 + [DPRC_SET_LOCKED] = { 152 + .cmdid_value = 0x16B0, 153 + .cmdid_mask = 0xFFF0, 154 + .token = true, 155 + .size = 16, 156 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 157 + }, 158 + [DPRC_CONNECT] = { 159 + .cmdid_value = 0x1670, 160 + .cmdid_mask = 0xFFF0, 161 + .token = true, 162 + .size = 56, 163 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 164 + }, 165 + [DPRC_DISCONNECT] = { 166 + .cmdid_value = 0x1680, 167 + .cmdid_mask = 0xFFF0, 168 + .token = true, 169 + .size = 32, 170 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 171 + }, 172 + [DPRC_GET_POOL] = { 173 + .cmdid_value = 0x1690, 174 + .cmdid_mask = 0xFFF0, 175 + .token = true, 176 + .size = 12, 177 + }, 178 + [DPRC_GET_POOL_COUNT] = { 179 + .cmdid_value = 0x16A0, 180 + .cmdid_mask = 0xFFF0, 181 + .token = true, 182 + .size = 8, 183 + }, 184 + [DPRC_GET_CONNECTION] = { 185 + .cmdid_value = 0x16C0, 186 + .cmdid_mask = 0xFFF0, 187 + .token = true, 188 + .size = 32, 189 + }, 190 + 191 + [DPCI_GET_LINK_STATE] = { 192 + .cmdid_value = 0x0E10, 193 + .cmdid_mask = 0xFFF0, 194 + .token = true, 195 + .size = 8, 196 + }, 197 + [DPCI_GET_PEER_ATTR] = { 198 + .cmdid_value = 0x0E20, 199 + .cmdid_mask = 0xFFF0, 200 + .token = true, 201 + .size = 8, 202 + }, 203 + [DPAIOP_GET_SL_VERSION] = { 204 + .cmdid_value = 0x2820, 205 + .cmdid_mask = 0xFFF0, 206 + .token = true, 207 + .size = 8, 208 + }, 209 + [DPAIOP_GET_STATE] = { 210 + .cmdid_value = 0x2830, 211 + .cmdid_mask = 0xFFF0, 212 + .token = true, 213 + .size = 8, 214 + }, 215 + [DPMNG_GET_VERSION] = { 216 + .cmdid_value = 0x8310, 217 + .cmdid_mask = 0xFFF0, 218 + .token = false, 219 + .size = 8, 220 + }, 221 + [DPSECI_GET_TX_QUEUE] = { 222 + .cmdid_value = 0x1970, 223 + .cmdid_mask = 0xFFF0, 224 + .token = true, 225 + .size = 14, 226 + }, 227 + [DPMAC_GET_COUNTER] = { 228 + .cmdid_value = 0x0c40, 229 + .cmdid_mask = 0xFFF0, 230 + .token = true, 231 + .size = 9, 232 + }, 233 + [DPMAC_GET_MAC_ADDR] = { 234 + .cmdid_value = 0x0c50, 235 + .cmdid_mask = 0xFFF0, 236 + .token = true, 237 + .size = 8, 238 + }, 239 + [DPNI_SET_PRIM_MAC] = { 240 + .cmdid_value = 0x2240, 241 + .cmdid_mask = 0xFFF0, 242 + .token = true, 243 + .size = 16, 244 + .flags = FSL_MC_CAP_NET_ADMIN_NEEDED, 245 + }, 246 + [DPNI_GET_PRIM_MAC] = { 247 + .cmdid_value = 0x2250, 248 + .cmdid_mask = 0xFFF0, 249 + .token = true, 250 + .size = 8, 251 + }, 252 + [DPNI_GET_STATISTICS] = { 253 + .cmdid_value = 0x25D0, 254 + .cmdid_mask = 0xFFF0, 255 + .token = true, 256 + .size = 10, 257 + }, 258 + [DPNI_GET_LINK_STATE] = { 259 + .cmdid_value = 0x2150, 260 + .cmdid_mask = 0xFFF0, 261 + .token = true, 262 + .size = 8, 263 + }, 264 + [GET_ATTR] = { 265 + .cmdid_value = 0x0040, 266 + .cmdid_mask = 0xFFF0, 267 + .token = true, 268 + .size = 8, 269 + }, 270 + [GET_IRQ_MASK] = { 271 + .cmdid_value = 0x0150, 272 + .cmdid_mask = 0xFFF0, 273 + .token = true, 274 + .size = 13, 275 + }, 276 + [GET_IRQ_STATUS] = { 277 + .cmdid_value = 0x0160, 278 + .cmdid_mask = 0xFFF0, 279 + .token = true, 280 + .size = 13, 281 + }, 282 + [CLOSE] = { 283 + .cmdid_value = 0x8000, 284 + .cmdid_mask = 0xFFF0, 285 + .token = true, 286 + .size = 8, 287 + }, 288 + 289 + /* Common commands amongst all types of objects. Must be checked last. */ 290 + [OPEN] = { 291 + .cmdid_value = 0x8000, 292 + .cmdid_mask = 0xFC00, 293 + .token = false, 294 + .size = 12, 295 + .flags = FSL_MC_CHECK_MODULE_ID, 296 + }, 297 + [GET_API_VERSION] = { 298 + .cmdid_value = 0xA000, 299 + .cmdid_mask = 0xFC00, 300 + .token = false, 301 + .size = 8, 302 + .flags = FSL_MC_CHECK_MODULE_ID, 303 + }, 304 + [DESTROY] = { 305 + .cmdid_value = 0x9800, 306 + .cmdid_mask = 0xFC00, 307 + .token = true, 308 + .size = 12, 309 + .flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED, 310 + }, 311 + [CREATE] = { 312 + .cmdid_value = 0x9000, 313 + .cmdid_mask = 0xFC00, 314 + .token = true, 315 + .size = 64, 316 + .flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED, 317 + }, 318 + }; 319 + 320 + #define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds) 321 + 322 + #define FSL_MC_MAX_MODULE_ID 0x10 323 + 324 + static int fsl_mc_command_check(struct fsl_mc_device *mc_dev, 325 + struct fsl_mc_command *mc_cmd) 326 + { 327 + struct fsl_mc_cmd_desc *desc = NULL; 328 + int mc_cmd_max_size, i; 329 + bool token_provided; 330 + u16 cmdid, module_id; 331 + char *mc_cmd_end; 332 + char sum = 0; 333 + 334 + /* Check if this is an accepted MC command */ 335 + cmdid = mc_cmd_hdr_read_cmdid(mc_cmd); 336 + for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) { 337 + desc = &fsl_mc_accepted_cmds[i]; 338 + if ((cmdid & desc->cmdid_mask) == desc->cmdid_value) 339 + break; 340 + } 341 + if (!desc) { 342 + dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid); 343 + return -EACCES; 344 + } 345 + 346 + /* Check if the size of the command is honored. Anything beyond the 347 + * last valid byte of the command should be zeroed. 348 + */ 349 + mc_cmd_max_size = sizeof(*mc_cmd); 350 + mc_cmd_end = ((char *)mc_cmd) + desc->size; 351 + for (i = desc->size; i < mc_cmd_max_size; i++) 352 + sum |= *mc_cmd_end++; 353 + if (sum) { 354 + dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n", 355 + cmdid, desc->size); 356 + return -EACCES; 357 + } 358 + 359 + /* Some MC commands request a token to be passed so that object 360 + * identification is possible. Check if the token passed in the command 361 + * is as expected. 362 + */ 363 + token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false; 364 + if (token_provided != desc->token) { 365 + dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n", 366 + cmdid, mc_cmd_hdr_read_token(mc_cmd)); 367 + return -EACCES; 368 + } 369 + 370 + /* If needed, check if the module ID passed is valid */ 371 + if (desc->flags & FSL_MC_CHECK_MODULE_ID) { 372 + /* The module ID is represented by bits [4:9] from the cmdid */ 373 + module_id = (cmdid & GENMASK(9, 4)) >> 4; 374 + if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) { 375 + dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n", 376 + cmdid, module_id); 377 + return -EACCES; 378 + } 379 + } 380 + 381 + /* Some commands alter how hardware resources are managed. For these 382 + * commands, check for CAP_NET_ADMIN. 383 + */ 384 + if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) { 385 + if (!capable(CAP_NET_ADMIN)) { 386 + dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n", 387 + cmdid); 388 + return -EPERM; 389 + } 390 + } 391 + 392 + return 0; 393 + } 394 + 395 + static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg, 396 + struct fsl_mc_io *mc_io) 397 + { 398 + struct fsl_mc_command mc_cmd; 399 + int error; 400 + 401 + error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd)); 402 + if (error) 403 + return -EFAULT; 404 + 405 + error = fsl_mc_command_check(mc_dev, &mc_cmd); 406 + if (error) 407 + return error; 408 + 409 + error = mc_send_command(mc_io, &mc_cmd); 410 + if (error) 411 + return error; 412 + 413 + error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd)); 414 + if (error) 415 + return -EFAULT; 416 + 417 + return 0; 418 + } 419 + 420 + static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep) 421 + { 422 + struct fsl_mc_device *root_mc_device; 423 + struct uapi_priv_data *priv_data; 424 + struct fsl_mc_io *dynamic_mc_io; 425 + struct fsl_mc_uapi *mc_uapi; 426 + struct fsl_mc_bus *mc_bus; 427 + int error; 428 + 429 + priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL); 430 + if (!priv_data) 431 + return -ENOMEM; 432 + 433 + mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc); 434 + mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc); 435 + root_mc_device = &mc_bus->mc_dev; 436 + 437 + mutex_lock(&mc_uapi->mutex); 438 + 439 + if (!mc_uapi->local_instance_in_use) { 440 + priv_data->mc_io = mc_uapi->static_mc_io; 441 + mc_uapi->local_instance_in_use = 1; 442 + } else { 443 + error = fsl_mc_portal_allocate(root_mc_device, 0, 444 + &dynamic_mc_io); 445 + if (error) { 446 + dev_dbg(&root_mc_device->dev, 447 + "Could not allocate MC portal\n"); 448 + goto error_portal_allocate; 449 + } 450 + 451 + priv_data->mc_io = dynamic_mc_io; 452 + } 453 + priv_data->uapi = mc_uapi; 454 + filep->private_data = priv_data; 455 + 456 + mutex_unlock(&mc_uapi->mutex); 457 + 458 + return 0; 459 + 460 + error_portal_allocate: 461 + mutex_unlock(&mc_uapi->mutex); 462 + kfree(priv_data); 463 + 464 + return error; 465 + } 466 + 467 + static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep) 468 + { 469 + struct uapi_priv_data *priv_data; 470 + struct fsl_mc_uapi *mc_uapi; 471 + struct fsl_mc_io *mc_io; 472 + 473 + priv_data = filep->private_data; 474 + mc_uapi = priv_data->uapi; 475 + mc_io = priv_data->mc_io; 476 + 477 + mutex_lock(&mc_uapi->mutex); 478 + 479 + if (mc_io == mc_uapi->static_mc_io) 480 + mc_uapi->local_instance_in_use = 0; 481 + else 482 + fsl_mc_portal_free(mc_io); 483 + 484 + kfree(filep->private_data); 485 + filep->private_data = NULL; 486 + 487 + mutex_unlock(&mc_uapi->mutex); 488 + 489 + return 0; 490 + } 491 + 492 + static long fsl_mc_uapi_dev_ioctl(struct file *file, 493 + unsigned int cmd, 494 + unsigned long arg) 495 + { 496 + struct uapi_priv_data *priv_data = file->private_data; 497 + struct fsl_mc_device *root_mc_device; 498 + struct fsl_mc_bus *mc_bus; 499 + int error; 500 + 501 + mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc); 502 + root_mc_device = &mc_bus->mc_dev; 503 + 504 + switch (cmd) { 505 + case FSL_MC_SEND_MC_COMMAND: 506 + error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io); 507 + break; 508 + default: 509 + dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n"); 510 + error = -EINVAL; 511 + } 512 + 513 + return error; 514 + } 515 + 516 + static const struct file_operations fsl_mc_uapi_dev_fops = { 517 + .owner = THIS_MODULE, 518 + .open = fsl_mc_uapi_dev_open, 519 + .release = fsl_mc_uapi_dev_release, 520 + .unlocked_ioctl = fsl_mc_uapi_dev_ioctl, 521 + }; 522 + 523 + int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus) 524 + { 525 + struct fsl_mc_device *mc_dev = &mc_bus->mc_dev; 526 + struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc; 527 + int error; 528 + 529 + mc_uapi->misc.minor = MISC_DYNAMIC_MINOR; 530 + mc_uapi->misc.name = dev_name(&mc_dev->dev); 531 + mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops; 532 + 533 + error = misc_register(&mc_uapi->misc); 534 + if (error) 535 + return error; 536 + 537 + mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io; 538 + 539 + mutex_init(&mc_uapi->mutex); 540 + 541 + return 0; 542 + } 543 + 544 + void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus) 545 + { 546 + misc_deregister(&mc_bus->uapi_misc.misc); 547 + }
+9
include/uapi/linux/fsl_mc.h
··· 16 16 * struct fsl_mc_command - Management Complex (MC) command structure 17 17 * @header: MC command header 18 18 * @params: MC command parameters 19 + * 20 + * Used by FSL_MC_SEND_MC_COMMAND 19 21 */ 20 22 struct fsl_mc_command { 21 23 __le64 header; 22 24 __le64 params[MC_CMD_NUM_OF_PARAMS]; 23 25 }; 26 + 27 + #define FSL_MC_SEND_CMD_IOCTL_TYPE 'R' 28 + #define FSL_MC_SEND_CMD_IOCTL_SEQ 0xE0 29 + 30 + #define FSL_MC_SEND_MC_COMMAND \ 31 + _IOWR(FSL_MC_SEND_CMD_IOCTL_TYPE, FSL_MC_SEND_CMD_IOCTL_SEQ, \ 32 + struct fsl_mc_command) 24 33 25 34 #endif /* _UAPI_FSL_MC_H_ */