Skip to content

Commit eb5dfcb

Browse files
davejiangjgunthorpe
authored andcommitted
cxl: Add support to handle user feature commands for set feature
Add helper function to parse the user data from fwctl RPC ioctl and send the parsed input parameters to cxl_set_feature() call. Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Dan Williams <[email protected]> Reviewed-by: Li Ming <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 5908f3e commit eb5dfcb

File tree

2 files changed

+146
-2
lines changed

2 files changed

+146
-2
lines changed

drivers/cxl/core/features.c

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,21 @@ static const uuid_t cxl_exclusive_feats[] = {
2121
CXL_FEAT_RANK_SPARING_UUID,
2222
};
2323

24-
static bool is_cxl_feature_exclusive(struct cxl_feat_entry *entry)
24+
static bool is_cxl_feature_exclusive_by_uuid(const uuid_t *uuid)
2525
{
2626
for (int i = 0; i < ARRAY_SIZE(cxl_exclusive_feats); i++) {
27-
if (uuid_equal(&entry->uuid, &cxl_exclusive_feats[i]))
27+
if (uuid_equal(uuid, &cxl_exclusive_feats[i]))
2828
return true;
2929
}
3030

3131
return false;
3232
}
3333

34+
static bool is_cxl_feature_exclusive(struct cxl_feat_entry *entry)
35+
{
36+
return is_cxl_feature_exclusive_by_uuid(&entry->uuid);
37+
}
38+
3439
inline struct cxl_features_state *to_cxlfs(struct cxl_dev_state *cxlds)
3540
{
3641
return cxlds->cxlfs;
@@ -350,6 +355,27 @@ static void cxlctl_close_uctx(struct fwctl_uctx *uctx)
350355
{
351356
}
352357

358+
static struct cxl_feat_entry *
359+
get_support_feature_info(struct cxl_features_state *cxlfs,
360+
const struct fwctl_rpc_cxl *rpc_in)
361+
{
362+
struct cxl_feat_entry *feat;
363+
const uuid_t *uuid;
364+
365+
if (rpc_in->op_size < sizeof(uuid))
366+
return ERR_PTR(-EINVAL);
367+
368+
uuid = &rpc_in->set_feat_in.uuid;
369+
370+
for (int i = 0; i < cxlfs->entries->num_features; i++) {
371+
feat = &cxlfs->entries->ent[i];
372+
if (uuid_equal(uuid, &feat->uuid))
373+
return feat;
374+
}
375+
376+
return ERR_PTR(-EINVAL);
377+
}
378+
353379
static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
354380
const struct fwctl_rpc_cxl *rpc_in,
355381
size_t *out_len)
@@ -468,6 +494,116 @@ static void *cxlctl_get_feature(struct cxl_features_state *cxlfs,
468494
return no_free_ptr(rpc_out);
469495
}
470496

497+
static void *cxlctl_set_feature(struct cxl_features_state *cxlfs,
498+
const struct fwctl_rpc_cxl *rpc_in,
499+
size_t *out_len)
500+
{
501+
struct cxl_mailbox *cxl_mbox = &cxlfs->cxlds->cxl_mbox;
502+
const struct cxl_mbox_set_feat_in *feat_in;
503+
size_t out_size, data_size;
504+
u16 offset, return_code;
505+
u32 flags;
506+
int rc;
507+
508+
if (rpc_in->op_size <= sizeof(feat_in->hdr))
509+
return ERR_PTR(-EINVAL);
510+
511+
feat_in = &rpc_in->set_feat_in;
512+
513+
if (is_cxl_feature_exclusive_by_uuid(&feat_in->uuid))
514+
return ERR_PTR(-EPERM);
515+
516+
offset = le16_to_cpu(feat_in->offset);
517+
flags = le32_to_cpu(feat_in->flags);
518+
out_size = *out_len;
519+
520+
struct fwctl_rpc_cxl_out *rpc_out __free(kvfree) =
521+
kvzalloc(out_size, GFP_KERNEL);
522+
if (!rpc_out)
523+
return ERR_PTR(-ENOMEM);
524+
525+
rpc_out->size = 0;
526+
527+
data_size = rpc_in->op_size - sizeof(feat_in->hdr);
528+
rc = cxl_set_feature(cxl_mbox, &feat_in->uuid,
529+
feat_in->version, feat_in->feat_data,
530+
data_size, flags, offset, &return_code);
531+
if (rc) {
532+
rpc_out->retval = return_code;
533+
return no_free_ptr(rpc_out);
534+
}
535+
536+
rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS;
537+
*out_len = sizeof(*rpc_out);
538+
539+
return no_free_ptr(rpc_out);
540+
}
541+
542+
static bool cxlctl_validate_set_features(struct cxl_features_state *cxlfs,
543+
const struct fwctl_rpc_cxl *rpc_in,
544+
enum fwctl_rpc_scope scope)
545+
{
546+
u16 effects, imm_mask, reset_mask;
547+
struct cxl_feat_entry *feat;
548+
u32 flags;
549+
550+
feat = get_support_feature_info(cxlfs, rpc_in);
551+
if (IS_ERR(feat))
552+
return false;
553+
554+
/* Ensure that the attribute is changeable */
555+
flags = le32_to_cpu(feat->flags);
556+
if (!(flags & CXL_FEATURE_F_CHANGEABLE))
557+
return false;
558+
559+
effects = le16_to_cpu(feat->effects);
560+
561+
/*
562+
* Reserved bits are set, rejecting since the effects is not
563+
* comprehended by the driver.
564+
*/
565+
if (effects & CXL_CMD_EFFECTS_RESERVED) {
566+
dev_warn_once(cxlfs->cxlds->dev,
567+
"Reserved bits set in the Feature effects field!\n");
568+
return false;
569+
}
570+
571+
/* Currently no user background command support */
572+
if (effects & CXL_CMD_BACKGROUND)
573+
return false;
574+
575+
/* Effects cause immediate change, highest security scope is needed */
576+
imm_mask = CXL_CMD_CONFIG_CHANGE_IMMEDIATE |
577+
CXL_CMD_DATA_CHANGE_IMMEDIATE |
578+
CXL_CMD_POLICY_CHANGE_IMMEDIATE |
579+
CXL_CMD_LOG_CHANGE_IMMEDIATE;
580+
581+
reset_mask = CXL_CMD_CONFIG_CHANGE_COLD_RESET |
582+
CXL_CMD_CONFIG_CHANGE_CONV_RESET |
583+
CXL_CMD_CONFIG_CHANGE_CXL_RESET;
584+
585+
/* If no immediate or reset effect set, The hardware has a bug */
586+
if (!(effects & imm_mask) && !(effects & reset_mask))
587+
return false;
588+
589+
/*
590+
* If the Feature setting causes immediate configuration change
591+
* then we need the full write permission policy.
592+
*/
593+
if (effects & imm_mask && scope >= FWCTL_RPC_DEBUG_WRITE_FULL)
594+
return true;
595+
596+
/*
597+
* If the Feature setting only causes configuration change
598+
* after a reset, then the lesser level of write permission
599+
* policy is ok.
600+
*/
601+
if (!(effects & imm_mask) && scope >= FWCTL_RPC_DEBUG_WRITE)
602+
return true;
603+
604+
return false;
605+
}
606+
471607
static bool cxlctl_validate_hw_command(struct cxl_features_state *cxlfs,
472608
const struct fwctl_rpc_cxl *rpc_in,
473609
enum fwctl_rpc_scope scope,
@@ -483,6 +619,10 @@ static bool cxlctl_validate_hw_command(struct cxl_features_state *cxlfs,
483619
if (scope >= FWCTL_RPC_CONFIGURATION)
484620
return true;
485621
return false;
622+
case CXL_MBOX_OP_SET_FEATURE:
623+
if (cxl_mbox->feat_cap < CXL_FEATURES_RW)
624+
return false;
625+
return cxlctl_validate_set_features(cxlfs, rpc_in, scope);
486626
default:
487627
return false;
488628
}
@@ -497,6 +637,8 @@ static void *cxlctl_handle_commands(struct cxl_features_state *cxlfs,
497637
return cxlctl_get_supported_features(cxlfs, rpc_in, out_len);
498638
case CXL_MBOX_OP_GET_FEATURE:
499639
return cxlctl_get_feature(cxlfs, rpc_in, out_len);
640+
case CXL_MBOX_OP_SET_FEATURE:
641+
return cxlctl_set_feature(cxlfs, rpc_in, out_len);
500642
default:
501643
return ERR_PTR(-EOPNOTSUPP);
502644
}

include/uapi/fwctl/cxl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* @reserved1: Reserved. Must be 0s.
2020
* @get_sup_feats_in: Get Supported Features input
2121
* @get_feat_in: Get Feature input
22+
* @set_feat_in: Set Feature input
2223
*/
2324
struct fwctl_rpc_cxl {
2425
__struct_group(fwctl_rpc_cxl_hdr, hdr, /* no attrs */,
@@ -30,6 +31,7 @@ struct fwctl_rpc_cxl {
3031
union {
3132
struct cxl_mbox_get_sup_feats_in get_sup_feats_in;
3233
struct cxl_mbox_get_feat_in get_feat_in;
34+
struct cxl_mbox_set_feat_in set_feat_in;
3335
};
3436
};
3537

0 commit comments

Comments
 (0)