@@ -545,11 +545,12 @@ static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *
545545/* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
546546
547547struct tunable_attr_01 {
548- struct capdata01 * capdata ;
549548 struct device * dev ;
550- u32 feature_id ;
551- u32 device_id ;
552- u32 type_id ;
549+ u8 feature_id ;
550+ u8 device_id ;
551+ u8 type_id ;
552+ u8 cd_mode_id ; /* mode arg for searching capdata */
553+ u8 cv_mode_id ; /* mode arg for set/get current_value */
553554};
554555
555556static struct tunable_attr_01 ppt_pl1_spl = {
@@ -716,7 +717,7 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,
716717 int value , ret ;
717718
718719 attribute_id = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
719- LWMI_GZ_THERMAL_MODE_CUSTOM , tunable_attr -> type_id );
720+ tunable_attr -> cd_mode_id , tunable_attr -> type_id );
720721
721722 ret = lwmi_cd01_get_data (priv -> cd01_list , attribute_id , & capdata );
722723 if (ret )
@@ -771,7 +772,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
771772 struct wmi_method_args_32 args ;
772773 struct capdata01 capdata ;
773774 enum thermal_mode mode ;
774- u32 attribute_id ;
775775 u32 value ;
776776 int ret ;
777777
@@ -782,10 +782,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
782782 if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM )
783783 return - EBUSY ;
784784
785- attribute_id = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
786- mode , tunable_attr -> type_id );
785+ args . arg0 = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
786+ tunable_attr -> cd_mode_id , tunable_attr -> type_id );
787787
788- ret = lwmi_cd01_get_data (priv -> cd01_list , attribute_id , & capdata );
788+ ret = lwmi_cd01_get_data (priv -> cd01_list , args . arg0 , & capdata );
789789 if (ret )
790790 return ret ;
791791
@@ -796,7 +796,8 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
796796 if (value < capdata .min_value || value > capdata .max_value )
797797 return - EINVAL ;
798798
799- args .arg0 = attribute_id ;
799+ args .arg0 = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
800+ tunable_attr -> cv_mode_id , tunable_attr -> type_id );
800801 args .arg1 = value ;
801802
802803 ret = lwmi_dev_evaluate_int (priv -> wdev , 0x0 , LWMI_FEATURE_VALUE_SET ,
@@ -830,13 +831,16 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
830831 struct lwmi_om_priv * priv = dev_get_drvdata (tunable_attr -> dev );
831832 struct wmi_method_args_32 args ;
832833 enum thermal_mode mode ;
833- int retval ;
834- int ret ;
834+ int retval , ret ;
835835
836836 ret = lwmi_om_notifier_call (& mode );
837837 if (ret )
838838 return ret ;
839839
840+ /* If "no-mode" is the supported mode, ensure we never send current mode */
841+ if (tunable_attr -> cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE )
842+ mode = tunable_attr -> cv_mode_id ;
843+
840844 args .arg0 = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
841845 mode , tunable_attr -> type_id );
842846
@@ -849,6 +853,85 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
849853 return sysfs_emit (buf , "%d\n" , retval );
850854}
851855
856+ /**
857+ * lwmi_attr_01_is_supported() - Determine if the given attribute is supported.
858+ * @tunable_attr: The attribute to verify.
859+ *
860+ * First check if the attribute has a corresponding capdata01 table in the cd01
861+ * module under the "custom" mode (0xff). If that is not present then check if
862+ * there is a corresponding "no-mode" (0x00) entry. If either of those passes,
863+ * check capdata->supported for values > 0. If capdata is available, attempt to
864+ * determine the set/get mode for the current value property using a similar
865+ * pattern. If the value returned by either custom or no-mode is 0, or we get
866+ * an error, we assume that mode is not supported. If any of the above checks
867+ * fail then the attribute is not fully supported.
868+ *
869+ * The probed cd_mode_id/cv_mode_id are stored on the tunable_attr for later
870+ * reference.
871+ *
872+ * Return: Support level, or an error code.
873+ */
874+ static int lwmi_attr_01_is_supported (struct tunable_attr_01 * tunable_attr )
875+ {
876+ struct lwmi_om_priv * priv = dev_get_drvdata (tunable_attr -> dev );
877+ u8 mode = LWMI_GZ_THERMAL_MODE_CUSTOM ;
878+ struct wmi_method_args_32 args ;
879+ struct capdata01 capdata ;
880+ int retval , ret ;
881+
882+ /* Determine tunable_attr->cd_mode_id */
883+ no_mode_fallback_1 :
884+ args .arg0 = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
885+ mode , tunable_attr -> type_id );
886+
887+ ret = lwmi_cd01_get_data (priv -> cd01_list , args .arg0 , & capdata );
888+ if (ret && mode ) {
889+ dev_dbg (tunable_attr -> dev , "Attribute id %x not supported\n" , args .arg0 );
890+ mode = LWMI_GZ_THERMAL_MODE_NONE ;
891+ goto no_mode_fallback_1 ;
892+ }
893+ if (ret )
894+ goto not_supported ;
895+ if (!capdata .supported ) {
896+ ret = - EOPNOTSUPP ;
897+ goto not_supported ;
898+ }
899+
900+ tunable_attr -> cd_mode_id = mode ;
901+
902+ /* Determine tunable_attr->cv_mode_id */
903+ mode = LWMI_GZ_THERMAL_MODE_CUSTOM ;
904+ no_mode_fallback_2 :
905+ args .arg0 = LWMI_ATTR_ID (tunable_attr -> device_id , tunable_attr -> feature_id ,
906+ mode , tunable_attr -> type_id );
907+
908+ ret = lwmi_dev_evaluate_int (priv -> wdev , 0x0 , LWMI_FEATURE_VALUE_GET ,
909+ (unsigned char * )& args , sizeof (args ),
910+ & retval );
911+ if ((ret && mode ) || (!retval && mode )) {
912+ dev_dbg (tunable_attr -> dev , "Attribute id %x not supported\n" , args .arg0 );
913+ mode = LWMI_GZ_THERMAL_MODE_NONE ;
914+ goto no_mode_fallback_2 ;
915+ }
916+ if (ret )
917+ goto not_supported ;
918+ if (retval == 0 ) {
919+ ret = - EOPNOTSUPP ;
920+ goto not_supported ;
921+ }
922+
923+ tunable_attr -> cv_mode_id = mode ;
924+ dev_dbg (tunable_attr -> dev , "cd_mode_id: %02x%02x%02x%02x, cv_mode_id: %#08x attribute support level: %x\n" ,
925+ tunable_attr -> device_id , tunable_attr -> feature_id , tunable_attr -> cd_mode_id ,
926+ tunable_attr -> type_id , args .arg0 , capdata .supported );
927+
928+ return capdata .supported ;
929+
930+ not_supported :
931+ dev_dbg (tunable_attr -> dev , "Attribute id %x not supported\n" , args .arg0 );
932+ return ret ;
933+ }
934+
852935/* Lenovo WMI Other Mode Attribute macros */
853936#define __LWMI_ATTR_RO (_func , _name ) \
854937 { \
@@ -972,19 +1055,21 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
9721055 }
9731056
9741057 for (i = 0 ; i < ARRAY_SIZE (cd01_attr_groups ) - 1 ; i ++ ) {
975- err = sysfs_create_group (& priv -> fw_attr_kset -> kobj ,
976- cd01_attr_groups [i ].attr_group );
977- if (err )
978- goto err_remove_groups ;
979-
9801058 cd01_attr_groups [i ].tunable_attr -> dev = & priv -> wdev -> dev ;
1059+ if (lwmi_attr_01_is_supported (cd01_attr_groups [i ].tunable_attr ) > 0 ) {
1060+ err = sysfs_create_group (& priv -> fw_attr_kset -> kobj ,
1061+ cd01_attr_groups [i ].attr_group );
1062+ if (err )
1063+ goto err_remove_groups ;
1064+ }
9811065 }
9821066 return 0 ;
9831067
9841068err_remove_groups :
9851069 while (i -- )
986- sysfs_remove_group (& priv -> fw_attr_kset -> kobj ,
987- cd01_attr_groups [i ].attr_group );
1070+ if (lwmi_attr_01_is_supported (cd01_attr_groups [i ].tunable_attr ) > 0 )
1071+ sysfs_remove_group (& priv -> fw_attr_kset -> kobj ,
1072+ cd01_attr_groups [i ].attr_group );
9881073
9891074 kset_unregister (priv -> fw_attr_kset );
9901075
0 commit comments