-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert kernel hwmon interface to use PWM (0-255) intsead of RPM #261
base: main
Are you sure you want to change the base?
Changes from 1 commit
241c023
b44ee8f
4ef6609
fb7db66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1455,7 +1455,7 @@ static int acpi_process_buffer_to_ints(const char *id_name, int id_nr, | |
//} | ||
|
||
static int wmi_exec_ints(const char *guid, u8 instance, u32 method_id, | ||
const struct acpi_buffer *params, u8 *res, | ||
const struct acpi_buffer *params, void *res, | ||
size_t ressize) | ||
{ | ||
acpi_status status; | ||
|
@@ -1518,7 +1518,7 @@ static int wmi_exec_noarg_int(const char *guid, u8 instance, u32 method_id, | |
} | ||
|
||
static int wmi_exec_noarg_ints(const char *guid, u8 instance, u32 method_id, | ||
u8 *res, size_t ressize) | ||
void *res, size_t ressize) | ||
{ | ||
struct acpi_buffer params; | ||
|
||
|
@@ -1712,6 +1712,12 @@ enum OtherMethodFeature { | |
OtherMethodFeature_C_U1 = 0x05010000, | ||
OtherMethodFeature_TEMP_CPU = 0x05040000, | ||
OtherMethodFeature_TEMP_GPU = 0x05050000, | ||
OtherMethodFeature_FAN_FULLSPEED = 0x04020000, | ||
}; | ||
|
||
struct other_method_val { | ||
u32 param; | ||
u32 val; | ||
}; | ||
|
||
static ssize_t wmi_other_method_get_value(enum OtherMethodFeature feature_id, | ||
|
@@ -1731,6 +1737,20 @@ static ssize_t wmi_other_method_get_value(enum OtherMethodFeature feature_id, | |
return error; | ||
} | ||
|
||
static ssize_t wmi_other_method_set_value(enum OtherMethodFeature feature_id, | ||
int value) | ||
{ | ||
int error; | ||
struct other_method_val param = { | ||
.param=feature_id, | ||
.val=value | ||
}; | ||
|
||
error = wmi_exec_arg(LEGION_WMI_LENOVO_OTHER_METHOD_GUID, 0, | ||
WMI_METHOD_ID_SET_FEATURE_VALUE, ¶m, sizeof(param)); | ||
return error; | ||
} | ||
|
||
/* =================================== */ | ||
/* EC RAM Access with memory mapped IO */ | ||
/* =================================== */ | ||
|
@@ -2828,10 +2848,23 @@ struct WMIFanTable { | |
u16 FSS7; | ||
u16 FSS8; | ||
u16 FSS9; | ||
u8 FSSNULL; | ||
u32 FTLE; | ||
u16 FST0; | ||
u16 FST1; | ||
u16 FST2; | ||
u16 FST3; | ||
u16 FST4; | ||
u16 FST5; | ||
u16 FST6; | ||
u16 FST7; | ||
u16 FST8; | ||
u16 FST9; | ||
u8 FSTNULL; | ||
} __packed; | ||
|
||
struct WMIFanTableRead { | ||
u32 FSFL; | ||
u32 FSTL; | ||
u32 FSS0; | ||
u32 FSS1; | ||
u32 FSS2; | ||
|
@@ -2842,84 +2875,93 @@ struct WMIFanTableRead { | |
u32 FSS7; | ||
u32 FSS8; | ||
u32 FSS9; | ||
u32 FSSA; | ||
// Ignored for now | ||
u32 FTLE; | ||
u32 FST0; | ||
u32 FST1; | ||
u32 FST2; | ||
u32 FST3; | ||
u32 FST4; | ||
u32 FST5; | ||
u32 FST6; | ||
u32 FST7; | ||
u32 FST8; | ||
u32 FST9; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is FTLE? Length? |
||
} __packed; | ||
|
||
static ssize_t wmi_read_fancurve_custom(const struct model_config *model, | ||
struct fancurve *fancurve) | ||
{ | ||
u8 buffer[88]; | ||
struct WMIFanTableRead fantable; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea. By adding this new fields we get exactly 88 Bytes. These fields where not defined in the ACPI code of other models. |
||
int err; | ||
|
||
// The output buffer from the ACPI call is 88 bytes and larger | ||
// than the returned object | ||
pr_info("Size of object: %lu\n", sizeof(struct WMIFanTableRead)); | ||
err = wmi_exec_noarg_ints(WMI_GUID_LENOVO_FAN_METHOD, 0, | ||
WMI_METHOD_ID_FAN_GET_TABLE, buffer, | ||
sizeof(buffer)); | ||
struct acpi_buffer params; | ||
u32 fanid = 0; | ||
params.length = sizeof(fanid); | ||
params.pointer = &fanid; | ||
|
||
err = wmi_exec_ints(WMI_GUID_LENOVO_FAN_METHOD, 0, | ||
WMI_METHOD_ID_FAN_GET_TABLE, ¶ms, &fantable, | ||
sizeof(fantable)); | ||
print_hex_dump(KERN_INFO, "legion_laptop fan table wmi buffer", | ||
DUMP_PREFIX_ADDRESS, 16, 1, buffer, sizeof(buffer), | ||
true); | ||
DUMP_PREFIX_ADDRESS, 16, 1, &fantable, | ||
sizeof(fantable), true); | ||
if (!err) { | ||
struct WMIFanTableRead *fantable = | ||
(struct WMIFanTableRead *)&buffer[0]; | ||
fancurve->current_point_i = 0; | ||
fancurve->size = 10; | ||
fancurve->size = fantable.FSTL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. This does not work for other models because FSTL is not set to 10 but just not set. |
||
fancurve->fan_speed_unit = FAN_SPEED_UNIT_PERCENT; | ||
fancurve->points[0].speed1 = fantable->FSS0; | ||
fancurve->points[1].speed1 = fantable->FSS1; | ||
fancurve->points[2].speed1 = fantable->FSS2; | ||
fancurve->points[3].speed1 = fantable->FSS3; | ||
fancurve->points[4].speed1 = fantable->FSS4; | ||
fancurve->points[5].speed1 = fantable->FSS5; | ||
fancurve->points[6].speed1 = fantable->FSS6; | ||
fancurve->points[7].speed1 = fantable->FSS7; | ||
fancurve->points[8].speed1 = fantable->FSS8; | ||
fancurve->points[9].speed1 = fantable->FSS9; | ||
//fancurve->points[10].speed1 = fantable->FSSA; | ||
fancurve->points[0].speed1 = fantable.FSS0; | ||
fancurve->points[1].speed1 = fantable.FSS1; | ||
fancurve->points[2].speed1 = fantable.FSS2; | ||
fancurve->points[3].speed1 = fantable.FSS3; | ||
fancurve->points[4].speed1 = fantable.FSS4; | ||
fancurve->points[5].speed1 = fantable.FSS5; | ||
fancurve->points[6].speed1 = fantable.FSS6; | ||
fancurve->points[7].speed1 = fantable.FSS7; | ||
fancurve->points[8].speed1 = fantable.FSS8; | ||
fancurve->points[9].speed1 = fantable.FSS9; | ||
//fancurve->points[10].speed1 = fantable.FSSA; | ||
} | ||
return err; | ||
} | ||
|
||
static ssize_t wmi_write_fancurve_custom(const struct model_config *model, | ||
const struct fancurve *fancurve) | ||
{ | ||
u8 buffer[0x20]; | ||
struct WMIFanTable fan; | ||
fan.FSTL = 10; | ||
fan.FSS0 = fancurve->points[0].speed1; | ||
fan.FSS1 = fancurve->points[1].speed1; | ||
fan.FSS2 = fancurve->points[2].speed1; | ||
fan.FSS3 = fancurve->points[3].speed1; | ||
fan.FSS4 = fancurve->points[4].speed1; | ||
fan.FSS5 = fancurve->points[5].speed1; | ||
fan.FSS6 = fancurve->points[6].speed1; | ||
fan.FSS7 = fancurve->points[7].speed1; | ||
fan.FSS8 = fancurve->points[8].speed1; | ||
fan.FSS9 = fancurve->points[9].speed1; | ||
fan.FSSNULL = 0; | ||
// TODO: These should be variable and may be set on later models | ||
// on Legion Go, they are hardcoded | ||
fan.FTLE = 10; | ||
fan.FST0 = 10; | ||
fan.FST1 = 20; | ||
fan.FST2 = 30; | ||
fan.FST3 = 40; | ||
fan.FST4 = 50; | ||
fan.FST5 = 60; | ||
fan.FST6 = 70; | ||
fan.FST7 = 80; | ||
fan.FST8 = 90; | ||
fan.FST9 = 100; | ||
fan.FSTNULL = 0; | ||
int err; | ||
|
||
// The buffer is read like this in ACPI firmware | ||
// | ||
// CreateByteField (Arg2, Zero, FSTM) | ||
// CreateByteField (Arg2, One, FSID) | ||
// CreateDWordField (Arg2, 0x02, FSTL) | ||
// CreateByteField (Arg2, 0x06, FSS0) | ||
// CreateByteField (Arg2, 0x08, FSS1) | ||
// CreateByteField (Arg2, 0x0A, FSS2) | ||
// CreateByteField (Arg2, 0x0C, FSS3) | ||
// CreateByteField (Arg2, 0x0E, FSS4) | ||
// CreateByteField (Arg2, 0x10, FSS5) | ||
// CreateByteField (Arg2, 0x12, FSS6) | ||
// CreateByteField (Arg2, 0x14, FSS7) | ||
// CreateByteField (Arg2, 0x16, FSS8) | ||
// CreateByteField (Arg2, 0x18, FSS9) | ||
|
||
memset(buffer, 0, sizeof(buffer)); | ||
buffer[0x06] = fancurve->points[0].speed1; | ||
buffer[0x08] = fancurve->points[1].speed1; | ||
buffer[0x0A] = fancurve->points[2].speed1; | ||
buffer[0x0C] = fancurve->points[3].speed1; | ||
buffer[0x0E] = fancurve->points[4].speed1; | ||
buffer[0x10] = fancurve->points[5].speed1; | ||
buffer[0x12] = fancurve->points[6].speed1; | ||
buffer[0x14] = fancurve->points[7].speed1; | ||
buffer[0x16] = fancurve->points[8].speed1; | ||
buffer[0x18] = fancurve->points[9].speed1; | ||
|
||
print_hex_dump(KERN_INFO, "legion_laptop fan table wmi write buffer", | ||
DUMP_PREFIX_ADDRESS, 16, 1, buffer, sizeof(buffer), | ||
DUMP_PREFIX_ADDRESS, 16, 1, &fan, sizeof(fan), | ||
true); | ||
err = wmi_exec_arg(WMI_GUID_LENOVO_FAN_METHOD, 0, | ||
WMI_METHOD_ID_FAN_SET_TABLE, buffer, sizeof(buffer)); | ||
WMI_METHOD_ID_FAN_SET_TABLE, &fan, sizeof(fan)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the old code we write a buffer of size 0x20. Now we write an object of size 0x34. Will this break stuff in old models? |
||
return err; | ||
} | ||
|
||
|
@@ -5694,6 +5736,34 @@ static struct attribute *fancurve_hwmon_attributes[] = { | |
&sensor_dev_attr_pwm1_mode.dev_attr.attr, NULL | ||
}; | ||
|
||
static struct attribute *fancurve_hwmon_attributes_legion_go[] = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why create new hwmon entries? Do we need new ones with other properties? |
||
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr, | ||
// These should be read only if the driver is properly implemented | ||
// and either fail to set or noop | ||
// &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess, we can make set read/write properties depending on model or just error out/ignore it. |
||
// &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr, | ||
// &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr, | ||
// | ||
&sensor_dev_attr_auto_points_size.dev_attr.attr, | ||
&sensor_dev_attr_pwm1_mode.dev_attr.attr, NULL | ||
}; | ||
|
||
static umode_t legion_hwmon_is_visible(struct kobject *kobj, | ||
struct attribute *attr, int idx) | ||
{ | ||
|
@@ -5720,6 +5790,11 @@ static const struct attribute_group legion_hwmon_fancurve_group = { | |
.is_visible = legion_hwmon_is_visible, | ||
}; | ||
|
||
static const struct attribute_group legion_go_hwmon_fancurve_group = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. I guess, this might be removed. |
||
.attrs = fancurve_hwmon_attributes_legion_go, | ||
.is_visible = legion_hwmon_is_visible, | ||
}; | ||
|
||
static const struct attribute_group *legion_hwmon_groups[] = { | ||
&legion_hwmon_sensor_group, &legion_hwmon_fancurve_group, NULL | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the source for that? Is there already a function that uses it that is not in this commit? Maybe you already have info how to use it. It is currently not used in this file.