Skip to content

Commit 4d1c09c

Browse files
davejiangjgunthorpe
authored andcommitted
cxl: Add support for fwctl RPC command to enable CXL feature commands
fwctl provides a fwctl_ops->fw_rpc() callback in order to issue ioctls to a device. The cxl fwctl driver will start by supporting the CXL Feature commands: Get Supported Features, Get Feature, and Set Feature. The fw_rpc() callback provides 'enum fwctl_rpc_scope' parameter where it indicates the security scope of the call. The Get Supported Features and Get Feature calls can be executed with the scope of FWCTL_RPC_CONFIGRATION. The Set Feature call is gated by the effects of the Feature reported by Get Supported Features call for the specific Feature. Only "Get Supported Features" is supported in this patch. Additional commands will be added in follow on patches. "Get Supported Features" will filter the Features that are exclusive to the kernel. The flag field of the Feature details will be cleared of the "Changeable" field and the "set feat size" will be set to 0 to indicate that the feature is not changeable. Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Dan Williams <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Li Ming <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 9b8e73c commit 4d1c09c

File tree

3 files changed

+166
-2
lines changed

3 files changed

+166
-2
lines changed

drivers/cxl/core/features.c

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/device.h>
55
#include <cxl/mailbox.h>
66
#include <cxl/features.h>
7+
#include <uapi/fwctl/cxl.h>
78
#include "cxl.h"
89
#include "core.h"
910
#include "cxlmem.h"
@@ -349,11 +350,127 @@ static void cxlctl_close_uctx(struct fwctl_uctx *uctx)
349350
{
350351
}
351352

353+
static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
354+
const struct fwctl_rpc_cxl *rpc_in,
355+
size_t *out_len)
356+
{
357+
const struct cxl_mbox_get_sup_feats_in *feat_in;
358+
struct cxl_mbox_get_sup_feats_out *feat_out;
359+
struct cxl_feat_entry *pos;
360+
size_t out_size;
361+
int requested;
362+
u32 count;
363+
u16 start;
364+
int i;
365+
366+
if (rpc_in->op_size != sizeof(*feat_in))
367+
return ERR_PTR(-EINVAL);
368+
369+
feat_in = &rpc_in->get_sup_feats_in;
370+
count = le32_to_cpu(feat_in->count);
371+
start = le16_to_cpu(feat_in->start_idx);
372+
requested = count / sizeof(*pos);
373+
374+
/*
375+
* Make sure that the total requested number of entries is not greater
376+
* than the total number of supported features allowed for userspace.
377+
*/
378+
if (start >= cxlfs->entries->num_features)
379+
return ERR_PTR(-EINVAL);
380+
381+
requested = min_t(int, requested, cxlfs->entries->num_features - start);
382+
383+
out_size = sizeof(struct fwctl_rpc_cxl_out) +
384+
struct_size(feat_out, ents, requested);
385+
386+
struct fwctl_rpc_cxl_out *rpc_out __free(kvfree) =
387+
kvzalloc(out_size, GFP_KERNEL);
388+
if (!rpc_out)
389+
return ERR_PTR(-ENOMEM);
390+
391+
rpc_out->size = struct_size(feat_out, ents, requested);
392+
feat_out = &rpc_out->get_sup_feats_out;
393+
if (requested == 0) {
394+
feat_out->num_entries = cpu_to_le16(requested);
395+
feat_out->supported_feats =
396+
cpu_to_le16(cxlfs->entries->num_features);
397+
rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS;
398+
*out_len = out_size;
399+
return no_free_ptr(rpc_out);
400+
}
401+
402+
for (i = start, pos = &feat_out->ents[0];
403+
i < cxlfs->entries->num_features; i++, pos++) {
404+
if (i - start == requested)
405+
break;
406+
407+
memcpy(pos, &cxlfs->entries->ent[i], sizeof(*pos));
408+
/*
409+
* If the feature is exclusive, set the set_feat_size to 0 to
410+
* indicate that the feature is not changeable.
411+
*/
412+
if (is_cxl_feature_exclusive(pos)) {
413+
u32 flags;
414+
415+
pos->set_feat_size = 0;
416+
flags = le32_to_cpu(pos->flags);
417+
flags &= ~CXL_FEATURE_F_CHANGEABLE;
418+
pos->flags = cpu_to_le32(flags);
419+
}
420+
}
421+
422+
feat_out->num_entries = cpu_to_le16(requested);
423+
feat_out->supported_feats = cpu_to_le16(cxlfs->entries->num_features);
424+
rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS;
425+
*out_len = out_size;
426+
427+
return no_free_ptr(rpc_out);
428+
}
429+
430+
static bool cxlctl_validate_hw_command(struct cxl_features_state *cxlfs,
431+
const struct fwctl_rpc_cxl *rpc_in,
432+
enum fwctl_rpc_scope scope,
433+
u16 opcode)
434+
{
435+
struct cxl_mailbox *cxl_mbox = &cxlfs->cxlds->cxl_mbox;
436+
437+
switch (opcode) {
438+
case CXL_MBOX_OP_GET_SUPPORTED_FEATURES:
439+
if (cxl_mbox->feat_cap < CXL_FEATURES_RO)
440+
return false;
441+
if (scope >= FWCTL_RPC_CONFIGURATION)
442+
return true;
443+
return false;
444+
default:
445+
return false;
446+
}
447+
}
448+
449+
static void *cxlctl_handle_commands(struct cxl_features_state *cxlfs,
450+
const struct fwctl_rpc_cxl *rpc_in,
451+
size_t *out_len, u16 opcode)
452+
{
453+
switch (opcode) {
454+
case CXL_MBOX_OP_GET_SUPPORTED_FEATURES:
455+
return cxlctl_get_supported_features(cxlfs, rpc_in, out_len);
456+
default:
457+
return ERR_PTR(-EOPNOTSUPP);
458+
}
459+
}
460+
352461
static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
353462
void *in, size_t in_len, size_t *out_len)
354463
{
355-
/* Place holder */
356-
return ERR_PTR(-EOPNOTSUPP);
464+
struct fwctl_device *fwctl_dev = uctx->fwctl;
465+
struct cxl_memdev *cxlmd = fwctl_to_memdev(fwctl_dev);
466+
struct cxl_features_state *cxlfs = to_cxlfs(cxlmd->cxlds);
467+
const struct fwctl_rpc_cxl *rpc_in = in;
468+
u16 opcode = rpc_in->opcode;
469+
470+
if (!cxlctl_validate_hw_command(cxlfs, rpc_in, scope, opcode))
471+
return ERR_PTR(-EINVAL);
472+
473+
return cxlctl_handle_commands(cxlfs, rpc_in, out_len, opcode);
357474
}
358475

359476
static const struct fwctl_ops cxlctl_ops = {

include/uapi/cxl/features.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct cxl_mbox_get_sup_feats_in {
4242
#define CXL_CMD_EFFECTS_VALID BIT(9)
4343
#define CXL_CMD_CONFIG_CHANGE_CONV_RESET BIT(10)
4444
#define CXL_CMD_CONFIG_CHANGE_CXL_RESET BIT(11)
45+
#define CXL_CMD_EFFECTS_RESERVED GENMASK(15, 12)
4546

4647
/*
4748
* struct cxl_feat_entry - Supported Feature Entry

include/uapi/fwctl/cxl.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
/*
3+
* Copyright (c) 2024-2025 Intel Corporation
4+
*
5+
* These are definitions for the mailbox command interface of CXL subsystem.
6+
*/
7+
#ifndef _UAPI_FWCTL_CXL_H_
8+
#define _UAPI_FWCTL_CXL_H_
9+
10+
#include <linux/types.h>
11+
#include <linux/stddef.h>
12+
#include <cxl/features.h>
13+
14+
/**
15+
* struct fwctl_rpc_cxl - ioctl(FWCTL_RPC) input for CXL
16+
* @opcode: CXL mailbox command opcode
17+
* @flags: Flags for the command (input).
18+
* @op_size: Size of input payload.
19+
* @reserved1: Reserved. Must be 0s.
20+
* @get_sup_feats_in: Get Supported Features input
21+
*/
22+
struct fwctl_rpc_cxl {
23+
__struct_group(fwctl_rpc_cxl_hdr, hdr, /* no attrs */,
24+
__u32 opcode;
25+
__u32 flags;
26+
__u32 op_size;
27+
__u32 reserved1;
28+
);
29+
struct cxl_mbox_get_sup_feats_in get_sup_feats_in;
30+
};
31+
32+
/**
33+
* struct fwctl_rpc_cxl_out - ioctl(FWCTL_RPC) output for CXL
34+
* @size: Size of the output payload
35+
* @retval: Return value from device
36+
* @get_sup_feats_out: Get Supported Features output
37+
*/
38+
struct fwctl_rpc_cxl_out {
39+
__struct_group(fwctl_rpc_cxl_out_hdr, hdr, /* no attrs */,
40+
__u32 size;
41+
__u32 retval;
42+
);
43+
struct cxl_mbox_get_sup_feats_out get_sup_feats_out;
44+
};
45+
46+
#endif

0 commit comments

Comments
 (0)