| .. SPDX-License-Identifier: GPL-2.0 |
| |
| ================ |
| fwctl cxl driver |
| ================ |
| |
| :Author: Dave Jiang |
| |
| Overview |
| ======== |
| |
| The CXL spec defines a set of commands that can be issued to the mailbox of a |
| CXL device or switch. It also left room for vendor specific commands to be |
| issued to the mailbox as well. fwctl provides a path to issue a set of allowed |
| mailbox commands from user space to the device moderated by the kernel driver. |
| |
| The following 3 commands will be used to support CXL Features: |
| CXL spec r3.1 8.2.9.6.1 Get Supported Features (Opcode 0500h) |
| CXL spec r3.1 8.2.9.6.2 Get Feature (Opcode 0501h) |
| CXL spec r3.1 8.2.9.6.3 Set Feature (Opcode 0502h) |
| |
| The "Get Supported Features" return data may be filtered by the kernel driver to |
| drop any features that are forbidden by the kernel or being exclusively used by |
| the kernel. The driver will set the "Set Feature Size" of the "Get Supported |
| Features Supported Feature Entry" to 0 to indicate that the Feature cannot be |
| modified. The "Get Supported Features" command and the "Get Features" falls |
| under the fwctl policy of FWCTL_RPC_CONFIGURATION. |
| |
| For "Set Feature" command, the access policy currently is broken down into two |
| categories depending on the Set Feature effects reported by the device. If the |
| Set Feature will cause immediate change to the device, the fwctl access policy |
| must be FWCTL_RPC_DEBUG_WRITE_FULL. The effects for this level are |
| "immediate config change", "immediate data change", "immediate policy change", |
| or "immediate log change" for the set effects mask. If the effects are "config |
| change with cold reset" or "config change with conventional reset", then the |
| fwctl access policy must be FWCTL_RPC_DEBUG_WRITE or higher. |
| |
| fwctl cxl User API |
| ================== |
| |
| .. kernel-doc:: include/uapi/fwctl/cxl.h |
| |
| 1. Driver info query |
| -------------------- |
| |
| First step for the app is to issue the ioctl(FWCTL_CMD_INFO). Successful |
| invocation of the ioctl implies the Features capability is operational and |
| returns an all zeros 32bit payload. A ``struct fwctl_info`` needs to be filled |
| out with the ``fwctl_info.out_device_type`` set to ``FWCTL_DEVICE_TYPE_CXL``. |
| The return data should be ``struct fwctl_info_cxl`` that contains a reserved |
| 32bit field that should be all zeros. |
| |
| 2. Send hardware commands |
| ------------------------- |
| |
| Next step is to send the 'Get Supported Features' command to the driver from |
| user space via ioctl(FWCTL_RPC). A ``struct fwctl_rpc_cxl`` is pointed to |
| by ``fwctl_rpc.in``. ``struct fwctl_rpc_cxl.in_payload`` points to |
| the hardware input structure that is defined by the CXL spec. ``fwctl_rpc.out`` |
| points to the buffer that contains a ``struct fwctl_rpc_cxl_out`` that includes |
| the hardware output data inlined as ``fwctl_rpc_cxl_out.payload``. This command |
| is called twice. First time to retrieve the number of features supported. |
| A second time to retrieve the specific feature details as the output data. |
| |
| After getting the specific feature details, a Get/Set Feature command can be |
| appropriately programmed and sent. For a "Set Feature" command, the retrieved |
| feature info contains an effects field that details the resulting |
| "Set Feature" command will trigger. That will inform the user whether |
| the system is configured to allowed the "Set Feature" command or not. |
| |
| Code example of a Get Feature |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| .. code-block:: c |
| |
| static int cxl_fwctl_rpc_get_test_feature(int fd, struct test_feature *feat_ctx, |
| const uint32_t expected_data) |
| { |
| struct cxl_mbox_get_feat_in *feat_in; |
| struct fwctl_rpc_cxl_out *out; |
| struct fwctl_rpc rpc = {0}; |
| struct fwctl_rpc_cxl *in; |
| size_t out_size, in_size; |
| uint32_t val; |
| void *data; |
| int rc; |
| |
| in_size = sizeof(*in) + sizeof(*feat_in); |
| rc = posix_memalign((void **)&in, 16, in_size); |
| if (rc) |
| return -ENOMEM; |
| memset(in, 0, in_size); |
| feat_in = &in->get_feat_in; |
| |
| uuid_copy(feat_in->uuid, feat_ctx->uuid); |
| feat_in->count = feat_ctx->get_size; |
| |
| out_size = sizeof(*out) + feat_ctx->get_size; |
| rc = posix_memalign((void **)&out, 16, out_size); |
| if (rc) |
| goto free_in; |
| memset(out, 0, out_size); |
| |
| in->opcode = CXL_MBOX_OPCODE_GET_FEATURE; |
| in->op_size = sizeof(*feat_in); |
| |
| rpc.size = sizeof(rpc); |
| rpc.scope = FWCTL_RPC_CONFIGURATION; |
| rpc.in_len = in_size; |
| rpc.out_len = out_size; |
| rpc.in = (uint64_t)(uint64_t *)in; |
| rpc.out = (uint64_t)(uint64_t *)out; |
| |
| rc = send_command(fd, &rpc, out); |
| if (rc) |
| goto free_all; |
| |
| data = out->payload; |
| val = le32toh(*(__le32 *)data); |
| if (memcmp(&val, &expected_data, sizeof(val)) != 0) { |
| rc = -ENXIO; |
| goto free_all; |
| } |
| |
| free_all: |
| free(out); |
| free_in: |
| free(in); |
| return rc; |
| } |
| |
| Take a look at CXL CLI test directory |
| <https://github.com/pmem/ndctl/tree/main/test/fwctl.c> for a detailed user code |
| for examples on how to exercise this path. |
| |
| |
| fwctl cxl Kernel API |
| ==================== |
| |
| .. kernel-doc:: drivers/cxl/core/features.c |
| :export: |
| .. kernel-doc:: include/cxl/features.h |