@@ -550,6 +550,8 @@ struct tunable_attr_01 {
550550 u8 feature_id ;
551551 u8 device_id ;
552552 u8 type_id ;
553+ u8 cd_mode_id ; /* mode arg for searching capdata */
554+ u8 cv_mode_id ; /* mode arg for set/get current_value */
553555};
554556
555557static struct tunable_attr_01 ppt_pl1_spl = {
@@ -775,7 +777,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
775777 struct wmi_method_args_32 args = {};
776778 struct capdata01 capdata ;
777779 enum thermal_mode mode ;
778- u32 attribute_id ;
779780 u32 value ;
780781 int ret ;
781782
@@ -786,13 +787,12 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
786787 if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM )
787788 return - EBUSY ;
788789
789- attribute_id =
790- FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
791- FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
792- FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode ) |
793- FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
790+ args .arg0 = FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
791+ FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
792+ FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , tunable_attr -> cd_mode_id ) |
793+ FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
794794
795- ret = lwmi_cd01_get_data (priv -> cd01_list , attribute_id , & capdata );
795+ ret = lwmi_cd01_get_data (priv -> cd01_list , args . arg0 , & capdata );
796796 if (ret )
797797 return ret ;
798798
@@ -803,7 +803,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
803803 if (value < capdata .min_value || value > capdata .max_value )
804804 return - EINVAL ;
805805
806- args .arg0 = attribute_id ;
806+ args .arg0 = FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
807+ FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
808+ FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , tunable_attr -> cv_mode_id ) |
809+ FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
807810 args .arg1 = value ;
808811
809812 ret = lwmi_dev_evaluate_int (priv -> wdev , 0x0 , LWMI_FEATURE_VALUE_SET ,
@@ -837,21 +840,21 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
837840 struct lwmi_om_priv * priv = dev_get_drvdata (tunable_attr -> dev );
838841 struct wmi_method_args_32 args = {};
839842 enum thermal_mode mode ;
840- u32 attribute_id ;
841843 int retval ;
842844 int ret ;
843845
844846 ret = lwmi_om_notifier_call (& mode );
845847 if (ret )
846848 return ret ;
847849
848- attribute_id =
849- FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
850- FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
851- FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode ) |
852- FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
850+ /* If "no-mode" is the supported mode, ensure we never send current mode */
851+ if (tunable_attr -> cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE )
852+ mode = tunable_attr -> cv_mode_id ;
853853
854- args .arg0 = attribute_id ;
854+ args .arg0 = FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
855+ FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
856+ FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode ) |
857+ FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
855858
856859 ret = lwmi_dev_evaluate_int (priv -> wdev , 0x0 , LWMI_FEATURE_VALUE_GET ,
857860 (unsigned char * )& args , sizeof (args ),
@@ -862,6 +865,81 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
862865 return sysfs_emit (buf , "%d\n" , retval );
863866}
864867
868+ /**
869+ * lwmi_attr_01_is_supported() - Determine if the given attribute is supported.
870+ * @tunable_attr: The attribute to verify.
871+ *
872+ * First check if the attribute has a corresponding capdata01 table in the cd01
873+ * module under the "custom" mode (0xff). If that is not present then check if
874+ * there is a corresponding "no-mode" (0x00) entry. If either of those passes,
875+ * check capdata->supported for values > 0. If capdata is available, attempt to
876+ * determine the set/get mode for the current value property using a similar
877+ * pattern. If the value returned by either custom or no-mode is 0, or we get
878+ * an error, we assume that mode is not supported. If any of the above checks
879+ * fail then the attribute is not fully supported.
880+ *
881+ * The probed cd_mode_id/cv_mode_id are stored on the tunable_attr for later
882+ * reference.
883+ *
884+ * Return: bool.
885+ */
886+ static bool lwmi_attr_01_is_supported (struct tunable_attr_01 * tunable_attr )
887+ {
888+ u8 modes [2 ] = { LWMI_GZ_THERMAL_MODE_CUSTOM , LWMI_GZ_THERMAL_MODE_NONE };
889+ struct lwmi_om_priv * priv = dev_get_drvdata (tunable_attr -> dev );
890+ struct wmi_method_args_32 args = { 0x0 , 0x0 };
891+ bool cd_mode_found = false;
892+ bool cv_mode_found = false;
893+ struct capdata01 capdata ;
894+ int retval , ret , i ;
895+
896+ /* Determine tunable_attr->cd_mode_id*/
897+ for (i = 0 ; i < ARRAY_SIZE (modes ); i ++ ) {
898+ args .arg0 = FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
899+ FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
900+ FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , modes [i ]) |
901+ FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
902+
903+ ret = lwmi_cd01_get_data (priv -> cd01_list , args .arg0 , & capdata );
904+ if (ret || !capdata .supported )
905+ continue ;
906+ tunable_attr -> cd_mode_id = modes [i ];
907+ cd_mode_found = true;
908+ break ;
909+ }
910+
911+ if (!cd_mode_found )
912+ return cd_mode_found ;
913+
914+ dev_dbg (tunable_attr -> dev ,
915+ "cd_mode_id: %#010x\n" , args .arg0 );
916+
917+ /* Determine tunable_attr->cv_mode_id, returns 1 if supported*/
918+ for (i = 0 ; i < ARRAY_SIZE (modes ); i ++ ) {
919+ args .arg0 = FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr -> device_id ) |
920+ FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr -> feature_id ) |
921+ FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , modes [i ]) |
922+ FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr -> type_id );
923+
924+ ret = lwmi_dev_evaluate_int (priv -> wdev , 0x0 , LWMI_FEATURE_VALUE_GET ,
925+ (unsigned char * )& args , sizeof (args ),
926+ & retval );
927+ if (ret || !retval )
928+ continue ;
929+ tunable_attr -> cv_mode_id = modes [i ];
930+ cv_mode_found = true;
931+ break ;
932+ }
933+
934+ if (!cv_mode_found )
935+ return cv_mode_found ;
936+
937+ dev_dbg (tunable_attr -> dev , "cv_mode_id: %#010x, attribute support level: %#010x\n" ,
938+ args .arg0 , capdata .supported );
939+
940+ return capdata .supported > 0 ? true : false;
941+ }
942+
865943/* Lenovo WMI Other Mode Attribute macros */
866944#define __LWMI_ATTR_RO (_func , _name ) \
867945 { \
@@ -985,12 +1063,14 @@ static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
9851063 }
9861064
9871065 for (i = 0 ; i < ARRAY_SIZE (cd01_attr_groups ) - 1 ; i ++ ) {
1066+ cd01_attr_groups [i ].tunable_attr -> dev = & priv -> wdev -> dev ;
1067+ if (!lwmi_attr_01_is_supported (cd01_attr_groups [i ].tunable_attr ))
1068+ continue ;
1069+
9881070 err = sysfs_create_group (& priv -> fw_attr_kset -> kobj ,
9891071 cd01_attr_groups [i ].attr_group );
9901072 if (err )
9911073 goto err_remove_groups ;
992-
993- cd01_attr_groups [i ].tunable_attr -> dev = & priv -> wdev -> dev ;
9941074 }
9951075 return ;
9961076
0 commit comments