@@ -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+
3439inline 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+
353379static 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+
471607static 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 }
0 commit comments