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

cxl: Refactor user ioctl command path from mds to mailbox

With 'struct cxl_mailbox' context introduced, the helper functions
cxl_query_cmd() and cxl_send_cmd() can take a cxl_mailbox directly
rather than a cxl_memdev parameter. Refactor to use cxl_mailbox
directly.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Link: https://patch.msgid.link/20250204220430.4146187-2-dave.jiang@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

+101 -96
+4 -2
drivers/cxl/core/core.h
··· 4 4 #ifndef __CXL_CORE_H__ 5 5 #define __CXL_CORE_H__ 6 6 7 + #include <cxl/mailbox.h> 8 + 7 9 extern const struct device_type cxl_nvdimm_bridge_type; 8 10 extern const struct device_type cxl_nvdimm_type; 9 11 extern const struct device_type cxl_pmu_type; ··· 67 65 68 66 struct cxl_send_command; 69 67 struct cxl_mem_query_commands; 70 - int cxl_query_cmd(struct cxl_memdev *cxlmd, 68 + int cxl_query_cmd(struct cxl_mailbox *cxl_mbox, 71 69 struct cxl_mem_query_commands __user *q); 72 - int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s); 70 + int cxl_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_send_command __user *s); 73 71 void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, 74 72 resource_size_t length); 75 73
+42 -46
drivers/cxl/core/mbox.c
··· 349 349 return true; 350 350 } 351 351 352 - static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox, 353 - struct cxl_memdev_state *mds, u16 opcode, 352 + static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox_cmd, 353 + struct cxl_mailbox *cxl_mbox, u16 opcode, 354 354 size_t in_size, size_t out_size, u64 in_payload) 355 355 { 356 - struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 357 - *mbox = (struct cxl_mbox_cmd) { 356 + *mbox_cmd = (struct cxl_mbox_cmd) { 358 357 .opcode = opcode, 359 358 .size_in = in_size, 360 359 }; 361 360 362 361 if (in_size) { 363 - mbox->payload_in = vmemdup_user(u64_to_user_ptr(in_payload), 364 - in_size); 365 - if (IS_ERR(mbox->payload_in)) 366 - return PTR_ERR(mbox->payload_in); 362 + mbox_cmd->payload_in = vmemdup_user(u64_to_user_ptr(in_payload), 363 + in_size); 364 + if (IS_ERR(mbox_cmd->payload_in)) 365 + return PTR_ERR(mbox_cmd->payload_in); 367 366 368 - if (!cxl_payload_from_user_allowed(opcode, mbox->payload_in)) { 369 - dev_dbg(mds->cxlds.dev, "%s: input payload not allowed\n", 367 + if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in)) { 368 + dev_dbg(cxl_mbox->host, "%s: input payload not allowed\n", 370 369 cxl_mem_opcode_to_name(opcode)); 371 - kvfree(mbox->payload_in); 370 + kvfree(mbox_cmd->payload_in); 372 371 return -EBUSY; 373 372 } 374 373 } 375 374 376 375 /* Prepare to handle a full payload for variable sized output */ 377 376 if (out_size == CXL_VARIABLE_PAYLOAD) 378 - mbox->size_out = cxl_mbox->payload_size; 377 + mbox_cmd->size_out = cxl_mbox->payload_size; 379 378 else 380 - mbox->size_out = out_size; 379 + mbox_cmd->size_out = out_size; 381 380 382 - if (mbox->size_out) { 383 - mbox->payload_out = kvzalloc(mbox->size_out, GFP_KERNEL); 384 - if (!mbox->payload_out) { 385 - kvfree(mbox->payload_in); 381 + if (mbox_cmd->size_out) { 382 + mbox_cmd->payload_out = kvzalloc(mbox_cmd->size_out, GFP_KERNEL); 383 + if (!mbox_cmd->payload_out) { 384 + kvfree(mbox_cmd->payload_in); 386 385 return -ENOMEM; 387 386 } 388 387 } ··· 396 397 397 398 static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd, 398 399 const struct cxl_send_command *send_cmd, 399 - struct cxl_memdev_state *mds) 400 + struct cxl_mailbox *cxl_mbox) 400 401 { 401 - struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 402 - 403 402 if (send_cmd->raw.rsvd) 404 403 return -EINVAL; 405 404 ··· 412 415 if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) 413 416 return -EPERM; 414 417 415 - dev_WARN_ONCE(mds->cxlds.dev, true, "raw command path used\n"); 418 + dev_WARN_ONCE(cxl_mbox->host, true, "raw command path used\n"); 416 419 417 420 *mem_cmd = (struct cxl_mem_command) { 418 421 .info = { ··· 428 431 429 432 static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd, 430 433 const struct cxl_send_command *send_cmd, 431 - struct cxl_memdev_state *mds) 434 + struct cxl_mailbox *cxl_mbox) 432 435 { 433 436 struct cxl_mem_command *c = &cxl_mem_commands[send_cmd->id]; 434 437 const struct cxl_command_info *info = &c->info; ··· 443 446 return -EINVAL; 444 447 445 448 /* Check that the command is enabled for hardware */ 446 - if (!test_bit(info->id, mds->enabled_cmds)) 449 + if (!test_bit(info->id, cxl_mbox->enabled_cmds)) 447 450 return -ENOTTY; 448 451 449 452 /* Check that the command is not claimed for exclusive kernel use */ 450 - if (test_bit(info->id, mds->exclusive_cmds)) 453 + if (test_bit(info->id, cxl_mbox->exclusive_cmds)) 451 454 return -EBUSY; 452 455 453 456 /* Check the input buffer is the expected size */ ··· 476 479 /** 477 480 * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. 478 481 * @mbox_cmd: Sanitized and populated &struct cxl_mbox_cmd. 479 - * @mds: The driver data for the operation 482 + * @cxl_mbox: CXL mailbox context 480 483 * @send_cmd: &struct cxl_send_command copied in from userspace. 481 484 * 482 485 * Return: ··· 491 494 * safe to send to the hardware. 492 495 */ 493 496 static int cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd, 494 - struct cxl_memdev_state *mds, 497 + struct cxl_mailbox *cxl_mbox, 495 498 const struct cxl_send_command *send_cmd) 496 499 { 497 - struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 498 500 struct cxl_mem_command mem_cmd; 499 501 int rc; 500 502 ··· 510 514 511 515 /* Sanitize and construct a cxl_mem_command */ 512 516 if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW) 513 - rc = cxl_to_mem_cmd_raw(&mem_cmd, send_cmd, mds); 517 + rc = cxl_to_mem_cmd_raw(&mem_cmd, send_cmd, cxl_mbox); 514 518 else 515 - rc = cxl_to_mem_cmd(&mem_cmd, send_cmd, mds); 519 + rc = cxl_to_mem_cmd(&mem_cmd, send_cmd, cxl_mbox); 516 520 517 521 if (rc) 518 522 return rc; 519 523 520 524 /* Sanitize and construct a cxl_mbox_cmd */ 521 - return cxl_mbox_cmd_ctor(mbox_cmd, mds, mem_cmd.opcode, 525 + return cxl_mbox_cmd_ctor(mbox_cmd, cxl_mbox, mem_cmd.opcode, 522 526 mem_cmd.info.size_in, mem_cmd.info.size_out, 523 527 send_cmd->in.payload); 524 528 } 525 529 526 - int cxl_query_cmd(struct cxl_memdev *cxlmd, 530 + int cxl_query_cmd(struct cxl_mailbox *cxl_mbox, 527 531 struct cxl_mem_query_commands __user *q) 528 532 { 529 - struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 530 - struct device *dev = &cxlmd->dev; 533 + struct device *dev = cxl_mbox->host; 531 534 struct cxl_mem_command *cmd; 532 535 u32 n_commands; 533 536 int j = 0; ··· 547 552 cxl_for_each_cmd(cmd) { 548 553 struct cxl_command_info info = cmd->info; 549 554 550 - if (test_bit(info.id, mds->enabled_cmds)) 555 + if (test_bit(info.id, cxl_mbox->enabled_cmds)) 551 556 info.flags |= CXL_MEM_COMMAND_FLAG_ENABLED; 552 - if (test_bit(info.id, mds->exclusive_cmds)) 557 + if (test_bit(info.id, cxl_mbox->exclusive_cmds)) 553 558 info.flags |= CXL_MEM_COMMAND_FLAG_EXCLUSIVE; 554 559 555 560 if (copy_to_user(&q->commands[j++], &info, sizeof(info))) ··· 564 569 565 570 /** 566 571 * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. 567 - * @mds: The driver data for the operation 572 + * @cxl_mbox: The mailbox context for the operation. 568 573 * @mbox_cmd: The validated mailbox command. 569 574 * @out_payload: Pointer to userspace's output payload. 570 575 * @size_out: (Input) Max payload size to copy out. ··· 585 590 * 586 591 * See cxl_send_cmd(). 587 592 */ 588 - static int handle_mailbox_cmd_from_user(struct cxl_memdev_state *mds, 593 + static int handle_mailbox_cmd_from_user(struct cxl_mailbox *cxl_mbox, 589 594 struct cxl_mbox_cmd *mbox_cmd, 590 595 u64 out_payload, s32 *size_out, 591 596 u32 *retval) 592 597 { 593 - struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 594 - struct device *dev = mds->cxlds.dev; 598 + struct device *dev = cxl_mbox->host; 595 599 int rc; 596 600 597 601 dev_dbg(dev, ··· 627 633 return rc; 628 634 } 629 635 630 - int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) 636 + int cxl_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_send_command __user *s) 631 637 { 632 - struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 633 - struct device *dev = &cxlmd->dev; 638 + struct device *dev = cxl_mbox->host; 634 639 struct cxl_send_command send; 635 640 struct cxl_mbox_cmd mbox_cmd; 636 641 int rc; ··· 639 646 if (copy_from_user(&send, s, sizeof(send))) 640 647 return -EFAULT; 641 648 642 - rc = cxl_validate_cmd_from_user(&mbox_cmd, mds, &send); 649 + rc = cxl_validate_cmd_from_user(&mbox_cmd, cxl_mbox, &send); 643 650 if (rc) 644 651 return rc; 645 652 646 - rc = handle_mailbox_cmd_from_user(mds, &mbox_cmd, send.out.payload, 653 + rc = handle_mailbox_cmd_from_user(cxl_mbox, &mbox_cmd, send.out.payload, 647 654 &send.out.size, &send.retval); 648 655 if (rc) 649 656 return rc; ··· 717 724 */ 718 725 static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) 719 726 { 727 + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 720 728 struct cxl_cel_entry *cel_entry; 721 729 const int cel_entries = size / sizeof(*cel_entry); 722 730 struct device *dev = mds->cxlds.dev; ··· 731 737 int enabled = 0; 732 738 733 739 if (cmd) { 734 - set_bit(cmd->info.id, mds->enabled_cmds); 740 + set_bit(cmd->info.id, cxl_mbox->enabled_cmds); 735 741 enabled++; 736 742 } 737 743 ··· 801 807 */ 802 808 int cxl_enumerate_cmds(struct cxl_memdev_state *mds) 803 809 { 810 + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 804 811 struct cxl_mbox_get_supported_logs *gsl; 805 812 struct device *dev = mds->cxlds.dev; 806 813 struct cxl_mem_command *cmd; ··· 840 845 /* In case CEL was bogus, enable some default commands. */ 841 846 cxl_for_each_cmd(cmd) 842 847 if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE) 843 - set_bit(cmd->info.id, mds->enabled_cmds); 848 + set_bit(cmd->info.id, cxl_mbox->enabled_cmds); 844 849 845 850 /* Found the required CEL */ 846 851 rc = 0; ··· 1443 1448 mutex_init(&mds->event.log_lock); 1444 1449 mds->cxlds.dev = dev; 1445 1450 mds->cxlds.reg_map.host = dev; 1451 + mds->cxlds.cxl_mbox.host = dev; 1446 1452 mds->cxlds.reg_map.resource = CXL_RESOURCE_NONE; 1447 1453 mds->cxlds.type = CXL_DEVTYPE_CLASSMEM; 1448 1454 mds->ram_perf.qos_class = CXL_QOS_CLASS_INVALID;
+15 -7
drivers/cxl/core/memdev.c
··· 564 564 void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, 565 565 unsigned long *cmds) 566 566 { 567 + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 568 + 567 569 down_write(&cxl_memdev_rwsem); 568 - bitmap_or(mds->exclusive_cmds, mds->exclusive_cmds, cmds, 569 - CXL_MEM_COMMAND_ID_MAX); 570 + bitmap_or(cxl_mbox->exclusive_cmds, cxl_mbox->exclusive_cmds, 571 + cmds, CXL_MEM_COMMAND_ID_MAX); 570 572 up_write(&cxl_memdev_rwsem); 571 573 } 572 574 EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, "CXL"); ··· 581 579 void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, 582 580 unsigned long *cmds) 583 581 { 582 + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 583 + 584 584 down_write(&cxl_memdev_rwsem); 585 - bitmap_andnot(mds->exclusive_cmds, mds->exclusive_cmds, cmds, 586 - CXL_MEM_COMMAND_ID_MAX); 585 + bitmap_andnot(cxl_mbox->exclusive_cmds, cxl_mbox->exclusive_cmds, 586 + cmds, CXL_MEM_COMMAND_ID_MAX); 587 587 up_write(&cxl_memdev_rwsem); 588 588 } 589 589 EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, "CXL"); ··· 660 656 static long __cxl_memdev_ioctl(struct cxl_memdev *cxlmd, unsigned int cmd, 661 657 unsigned long arg) 662 658 { 659 + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 660 + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 661 + 663 662 switch (cmd) { 664 663 case CXL_MEM_QUERY_COMMANDS: 665 - return cxl_query_cmd(cxlmd, (void __user *)arg); 664 + return cxl_query_cmd(cxl_mbox, (void __user *)arg); 666 665 case CXL_MEM_SEND_COMMAND: 667 - return cxl_send_cmd(cxlmd, (void __user *)arg); 666 + return cxl_send_cmd(cxl_mbox, (void __user *)arg); 668 667 default: 669 668 return -ENOTTY; 670 669 } ··· 1001 994 int devm_cxl_setup_fw_upload(struct device *host, struct cxl_memdev_state *mds) 1002 995 { 1003 996 struct cxl_dev_state *cxlds = &mds->cxlds; 997 + struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox; 1004 998 struct device *dev = &cxlds->cxlmd->dev; 1005 999 struct fw_upload *fwl; 1006 1000 1007 - if (!test_bit(CXL_MEM_COMMAND_ID_GET_FW_INFO, mds->enabled_cmds)) 1001 + if (!test_bit(CXL_MEM_COMMAND_ID_GET_FW_INFO, cxl_mbox->enabled_cmds)) 1008 1002 return 0; 1009 1003 1010 1004 fwl = firmware_upload_register(THIS_MODULE, dev, dev_name(dev),
-40
drivers/cxl/cxlmem.h
··· 106 106 return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev); 107 107 } 108 108 109 - /** 110 - * struct cxl_mbox_cmd - A command to be submitted to hardware. 111 - * @opcode: (input) The command set and command submitted to hardware. 112 - * @payload_in: (input) Pointer to the input payload. 113 - * @payload_out: (output) Pointer to the output payload. Must be allocated by 114 - * the caller. 115 - * @size_in: (input) Number of bytes to load from @payload_in. 116 - * @size_out: (input) Max number of bytes loaded into @payload_out. 117 - * (output) Number of bytes generated by the device. For fixed size 118 - * outputs commands this is always expected to be deterministic. For 119 - * variable sized output commands, it tells the exact number of bytes 120 - * written. 121 - * @min_out: (input) internal command output payload size validation 122 - * @poll_count: (input) Number of timeouts to attempt. 123 - * @poll_interval_ms: (input) Time between mailbox background command polling 124 - * interval timeouts. 125 - * @return_code: (output) Error code returned from hardware. 126 - * 127 - * This is the primary mechanism used to send commands to the hardware. 128 - * All the fields except @payload_* correspond exactly to the fields described in 129 - * Command Register section of the CXL 2.0 8.2.8.4.5. @payload_in and 130 - * @payload_out are written to, and read from the Command Payload Registers 131 - * defined in CXL 2.0 8.2.8.4.8. 132 - */ 133 - struct cxl_mbox_cmd { 134 - u16 opcode; 135 - void *payload_in; 136 - void *payload_out; 137 - size_t size_in; 138 - size_t size_out; 139 - size_t min_out; 140 - int poll_count; 141 - int poll_interval_ms; 142 - u16 return_code; 143 - }; 144 - 145 109 /* 146 110 * Per CXL 3.0 Section 8.2.8.4.5.1 147 111 */ ··· 425 461 * @lsa_size: Size of Label Storage Area 426 462 * (CXL 2.0 8.2.9.5.1.1 Identify Memory Device) 427 463 * @firmware_version: Firmware version for the memory device. 428 - * @enabled_cmds: Hardware commands found enabled in CEL. 429 - * @exclusive_cmds: Commands that are kernel-internal only 430 464 * @total_bytes: sum of all possible capacities 431 465 * @volatile_only_bytes: hard volatile capacity 432 466 * @persistent_only_bytes: hard persistent capacity ··· 447 485 struct cxl_dev_state cxlds; 448 486 size_t lsa_size; 449 487 char firmware_version[0x10]; 450 - DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); 451 - DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); 452 488 u64 total_bytes; 453 489 u64 volatile_only_bytes; 454 490 u64 persistent_only_bytes;
+40 -1
include/cxl/mailbox.h
··· 3 3 #ifndef __CXL_MBOX_H__ 4 4 #define __CXL_MBOX_H__ 5 5 #include <linux/rcuwait.h> 6 + #include <uapi/linux/cxl_mem.h> 6 7 7 - struct cxl_mbox_cmd; 8 + /** 9 + * struct cxl_mbox_cmd - A command to be submitted to hardware. 10 + * @opcode: (input) The command set and command submitted to hardware. 11 + * @payload_in: (input) Pointer to the input payload. 12 + * @payload_out: (output) Pointer to the output payload. Must be allocated by 13 + * the caller. 14 + * @size_in: (input) Number of bytes to load from @payload_in. 15 + * @size_out: (input) Max number of bytes loaded into @payload_out. 16 + * (output) Number of bytes generated by the device. For fixed size 17 + * outputs commands this is always expected to be deterministic. For 18 + * variable sized output commands, it tells the exact number of bytes 19 + * written. 20 + * @min_out: (input) internal command output payload size validation 21 + * @poll_count: (input) Number of timeouts to attempt. 22 + * @poll_interval_ms: (input) Time between mailbox background command polling 23 + * interval timeouts. 24 + * @return_code: (output) Error code returned from hardware. 25 + * 26 + * This is the primary mechanism used to send commands to the hardware. 27 + * All the fields except @payload_* correspond exactly to the fields described in 28 + * Command Register section of the CXL 2.0 8.2.8.4.5. @payload_in and 29 + * @payload_out are written to, and read from the Command Payload Registers 30 + * defined in CXL 2.0 8.2.8.4.8. 31 + */ 32 + struct cxl_mbox_cmd { 33 + u16 opcode; 34 + void *payload_in; 35 + void *payload_out; 36 + size_t size_in; 37 + size_t size_out; 38 + size_t min_out; 39 + int poll_count; 40 + int poll_interval_ms; 41 + u16 return_code; 42 + }; 8 43 9 44 /** 10 45 * struct cxl_mailbox - context for CXL mailbox operations 11 46 * @host: device that hosts the mailbox 47 + * @enabled_cmds: mailbox commands that are enabled by the driver 48 + * @exclusive_cmds: mailbox commands that are exclusive to the kernel 12 49 * @payload_size: Size of space for payload 13 50 * (CXL 3.1 8.2.8.4.3 Mailbox Capabilities Register) 14 51 * @mbox_mutex: mutex protects device mailbox and firmware ··· 54 17 */ 55 18 struct cxl_mailbox { 56 19 struct device *host; 20 + DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); 21 + DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); 57 22 size_t payload_size; 58 23 struct mutex mbox_mutex; /* lock to protect mailbox context */ 59 24 struct rcuwait mbox_wait;