* [PATCH v2 0/2] ACPI / Fan: Performance states
@ 2019-12-13 23:48 Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 1/2] Documentation: ACPI: Documentation for Fan performance states Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 2/2] ACPI / fan: Display fan performance state information Srinivas Pandruvada
0 siblings, 2 replies; 4+ messages in thread
From: Srinivas Pandruvada @ 2019-12-13 23:48 UTC (permalink / raw)
To: rjw, corbet, lenb, rui.zhang
Cc: linux-doc, linux-kernel, linux-acpi, Srinivas Pandruvada
v2:
- Modified the presentation of performance state attributes
- Change the documentation to RST format
Srinivas Pandruvada (2):
Documentation: ACPI: Documentation for Fan performance states
ACPI / fan: Display fan performance state information
.../acpi/fan_performance_states.rst | 65 +++++++++++++
Documentation/admin-guide/acpi/index.rst | 1 +
drivers/acpi/fan.c | 96 +++++++++++++++++--
3 files changed, 154 insertions(+), 8 deletions(-)
create mode 100644 Documentation/admin-guide/acpi/fan_performance_states.rst
--
2.17.2
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] Documentation: ACPI: Documentation for Fan performance states
2019-12-13 23:48 [PATCH v2 0/2] ACPI / Fan: Performance states Srinivas Pandruvada
@ 2019-12-13 23:48 ` Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 2/2] ACPI / fan: Display fan performance state information Srinivas Pandruvada
1 sibling, 0 replies; 4+ messages in thread
From: Srinivas Pandruvada @ 2019-12-13 23:48 UTC (permalink / raw)
To: rjw, corbet, lenb, rui.zhang
Cc: linux-doc, linux-kernel, linux-acpi, Srinivas Pandruvada
Added documentation for performance states information for the ACPI
Fan object.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
.../acpi/fan_performance_states.rst | 65 +++++++++++++++++++
Documentation/admin-guide/acpi/index.rst | 1 +
2 files changed, 66 insertions(+)
create mode 100644 Documentation/admin-guide/acpi/fan_performance_states.rst
diff --git a/Documentation/admin-guide/acpi/fan_performance_states.rst b/Documentation/admin-guide/acpi/fan_performance_states.rst
new file mode 100644
index 000000000000..91f10738e158
--- /dev/null
+++ b/Documentation/admin-guide/acpi/fan_performance_states.rst
@@ -0,0 +1,65 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+ACPI Fan Performance States
+===========================
+
+When the optional object _FPS is present for ACPI devices PNP0C0B or INT3404,
+additional attributes are displayed under acpi device object. These attributes
+display information about each performance state.
+
+For more details about ACPI Fan _FPS please refer to the ACPI specification at:
+
+http://uefi.org/specifications
+
+Example display for INT3404 ACPI device folder::
+
+ $ ls -l /sys/bus/acpi/devices/INT3404:00/
+ total 0
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state0
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state1
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state10
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state11
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state2
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state3
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state4
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state5
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state6
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state7
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state8
+ -r--r--r-- 1 root root 4096 Dec 13 20:38 state9
+ -r--r--r-- 1 root root 4096 Dec 13 01:00 status
+ ...
+ ...
+
+In the above example, each of the state* attribute represent one performance
+state. Each performance state contains information about the properties of a
+state in the following format:
+
+control_percent:trip_point_index:speed_rpm:noise_level_mdb:power_mw
+
+For example::
+
+ $cat /sys/bus/acpi/devices/INT3404:00/state1
+ 25:0:3200:12500:1250
+
+Description of properties:
+
+* control_percent: Indicates the value to be used to set the fan speed to a
+specific level using the _FSL object. The value here is from 0-100 percent.
+
+* trip_point_index: The active cooling trip point number that corresponds to this
+performance state. The range is from 0-9.
+
+* speed_rpm: Indicates the speed of the fan in revolutions per minute.
+
+* noise_level_mdb: Indicates the audible noise emitted by the fan. By the
+specification the value represents the noise in 10ths of decibels. Here
+it is multiplied with 100 to present in milli-db, to avoid loss of
+precision.
+
+* power_mw: Indicates the power consumption in milliwatts.
+
+When the fields are not populated or invalid in the configuration,
+"not-defined" is displayed.
+
diff --git a/Documentation/admin-guide/acpi/index.rst b/Documentation/admin-guide/acpi/index.rst
index 4d13eeea1eca..71277689ad97 100644
--- a/Documentation/admin-guide/acpi/index.rst
+++ b/Documentation/admin-guide/acpi/index.rst
@@ -12,3 +12,4 @@ the Linux ACPI support.
dsdt-override
ssdt-overlays
cppc_sysfs
+ fan_performance_states
--
2.17.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] ACPI / fan: Display fan performance state information
2019-12-13 23:48 [PATCH v2 0/2] ACPI / Fan: Performance states Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 1/2] Documentation: ACPI: Documentation for Fan performance states Srinivas Pandruvada
@ 2019-12-13 23:48 ` Srinivas Pandruvada
2019-12-19 21:38 ` Rafael J. Wysocki
1 sibling, 1 reply; 4+ messages in thread
From: Srinivas Pandruvada @ 2019-12-13 23:48 UTC (permalink / raw)
To: rjw, corbet, lenb, rui.zhang
Cc: linux-doc, linux-kernel, linux-acpi, Srinivas Pandruvada
When _FPS object indicates support of variable speed fan, thermal cooling
devices for fan shows max performance state count using attribute
"max_state" greater than or equal to 1.
But the thermal cooling device doesn't display properties of each
performance state. This is not enough for smart fan control user space
software, which also considers speed, power and noise level.
This change presents fan performance states attributes under acpi
device for the fan. This will be under:
/sys/bus/acpi/devices/devices/INT3404:00
or
/sys/bus/platform/devices/PNP0C0B:00.
For example:
$ ls /sys/bus/acpi/devices/INT3404\:00
description path state0 state11 state4 state7 status
hid physical_node state1 state2 state5 state8 subsystem
modalias power state10 state3 state6 state9 uevent
uid wakeup
Here each state* attribute is representing a performance state.
Contents of state* attribute are formatted using:
control_percent:trip_point:speed_rpm:noise_level_mdb:power_mw
$ cat /sys/bus/acpi/devices/INT3404\:00/state10
95:0:11600:47500:4500
For more information refer to:
Documentation/acpi/fan_performance_states.txt
While here, return correct error from acpi_fan_probe() when
acpi_fan_get_fps() or acpi_fan_get_fif() fails.
Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/acpi/fan.c | 96 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 88 insertions(+), 8 deletions(-)
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 816b0803f7fb..86d2417953b5 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -44,12 +44,16 @@ static const struct dev_pm_ops acpi_fan_pm = {
#define FAN_PM_OPS_PTR NULL
#endif
+#define ACPI_FPS_NAME_LEN 20
+
struct acpi_fan_fps {
u64 control;
u64 trip_point;
u64 speed;
u64 noise_level;
u64 power;
+ char name[ACPI_FPS_NAME_LEN];
+ struct device_attribute dev_attr;
};
struct acpi_fan_fif {
@@ -265,6 +269,39 @@ static int acpi_fan_speed_cmp(const void *a, const void *b)
return fps1->speed - fps2->speed;
}
+static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
+ int count;
+
+ if (fps->control == 0xFFFFFFFF || fps->control > 100)
+ count = snprintf(buf, PAGE_SIZE, "not-defined:");
+ else
+ count = snprintf(buf, PAGE_SIZE, "%lld:", fps->control);
+
+ if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
+ count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+ else
+ count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->trip_point);
+
+ if (fps->speed == 0xFFFFFFFF)
+ count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+ else
+ count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->speed);
+
+ if (fps->noise_level == 0xFFFFFFFF)
+ count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+ else
+ count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->noise_level * 100);
+
+ if (fps->power == 0xFFFFFFFF)
+ count += snprintf(&buf[count], PAGE_SIZE, "not-defined\n");
+ else
+ count += snprintf(&buf[count], PAGE_SIZE, "%lld\n", fps->power);
+
+ return count;
+}
+
static int acpi_fan_get_fps(struct acpi_device *device)
{
struct acpi_fan *fan = acpi_driver_data(device);
@@ -295,12 +332,13 @@ static int acpi_fan_get_fps(struct acpi_device *device)
}
for (i = 0; i < fan->fps_count; i++) {
struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
- struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
+ struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
+ &fan->fps[i] };
status = acpi_extract_package(&obj->package.elements[i + 1],
&format, &fps);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Invalid _FPS element\n");
- break;
+ goto err;
}
}
@@ -308,6 +346,24 @@ static int acpi_fan_get_fps(struct acpi_device *device)
sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
acpi_fan_speed_cmp, NULL);
+ for (i = 0; i < fan->fps_count; ++i) {
+ struct acpi_fan_fps *fps = &fan->fps[i];
+
+ snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
+ fps->dev_attr.show = show_state;
+ fps->dev_attr.store = NULL;
+ fps->dev_attr.attr.name = fps->name;
+ fps->dev_attr.attr.mode = 0444;
+ status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
+ if (status) {
+ int j;
+
+ for (j = 0; j < i; ++j)
+ sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
+ break;
+ }
+ }
+
err:
kfree(obj);
return status;
@@ -330,14 +386,20 @@ static int acpi_fan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fan);
if (acpi_fan_is_acpi4(device)) {
- if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
- goto end;
+ result = acpi_fan_get_fif(device);
+ if (result)
+ return result;
+
+ result = acpi_fan_get_fps(device);
+ if (result)
+ return result;
+
fan->acpi4 = true;
} else {
result = acpi_device_update_power(device, NULL);
if (result) {
dev_err(&device->dev, "Failed to set initial power state\n");
- goto end;
+ goto err_end;
}
}
@@ -350,7 +412,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
&fan_cooling_ops);
if (IS_ERR(cdev)) {
result = PTR_ERR(cdev);
- goto end;
+ goto err_end;
}
dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
@@ -365,10 +427,21 @@ static int acpi_fan_probe(struct platform_device *pdev)
result = sysfs_create_link(&cdev->device.kobj,
&pdev->dev.kobj,
"device");
- if (result)
+ if (result) {
dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
+ goto err_end;
+ }
+
+ return 0;
+
+err_end:
+ if (fan->acpi4) {
+ int i;
+
+ for (i = 0; i < fan->fps_count; ++i)
+ sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
+ }
-end:
return result;
}
@@ -376,6 +449,13 @@ static int acpi_fan_remove(struct platform_device *pdev)
{
struct acpi_fan *fan = platform_get_drvdata(pdev);
+ if (fan->acpi4) {
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ int i;
+
+ for (i = 0; i < fan->fps_count; ++i)
+ sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
+ }
sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
sysfs_remove_link(&fan->cdev->device.kobj, "device");
thermal_cooling_device_unregister(fan->cdev);
--
2.17.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 2/2] ACPI / fan: Display fan performance state information
2019-12-13 23:48 ` [PATCH v2 2/2] ACPI / fan: Display fan performance state information Srinivas Pandruvada
@ 2019-12-19 21:38 ` Rafael J. Wysocki
0 siblings, 0 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2019-12-19 21:38 UTC (permalink / raw)
To: Srinivas Pandruvada
Cc: Rafael J. Wysocki, Jonathan Corbet, Len Brown, Zhang, Rui,
open list:DOCUMENTATION, Linux Kernel Mailing List,
ACPI Devel Maling List
On Sat, Dec 14, 2019 at 12:48 AM Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
>
> When _FPS object indicates support of variable speed fan, thermal cooling
> devices for fan shows max performance state count using attribute
> "max_state" greater than or equal to 1.
>
> But the thermal cooling device doesn't display properties of each
> performance state. This is not enough for smart fan control user space
> software, which also considers speed, power and noise level.
>
> This change presents fan performance states attributes under acpi
> device for the fan. This will be under:
> /sys/bus/acpi/devices/devices/INT3404:00
> or
> /sys/bus/platform/devices/PNP0C0B:00.
>
> For example:
> $ ls /sys/bus/acpi/devices/INT3404\:00
> description path state0 state11 state4 state7 status
> hid physical_node state1 state2 state5 state8 subsystem
> modalias power state10 state3 state6 state9 uevent
> uid wakeup
>
> Here each state* attribute is representing a performance state.
>
> Contents of state* attribute are formatted using:
> control_percent:trip_point:speed_rpm:noise_level_mdb:power_mw
>
> $ cat /sys/bus/acpi/devices/INT3404\:00/state10
> 95:0:11600:47500:4500
>
> For more information refer to:
> Documentation/acpi/fan_performance_states.txt
>
> While here, return correct error from acpi_fan_probe() when
> acpi_fan_get_fps() or acpi_fan_get_fif() fails.
>
> Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Folded the (rewritten) [1/2] into this one and queued it up for 5.6, thanks!
> ---
> drivers/acpi/fan.c | 96 ++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 88 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
> index 816b0803f7fb..86d2417953b5 100644
> --- a/drivers/acpi/fan.c
> +++ b/drivers/acpi/fan.c
> @@ -44,12 +44,16 @@ static const struct dev_pm_ops acpi_fan_pm = {
> #define FAN_PM_OPS_PTR NULL
> #endif
>
> +#define ACPI_FPS_NAME_LEN 20
> +
> struct acpi_fan_fps {
> u64 control;
> u64 trip_point;
> u64 speed;
> u64 noise_level;
> u64 power;
> + char name[ACPI_FPS_NAME_LEN];
> + struct device_attribute dev_attr;
> };
>
> struct acpi_fan_fif {
> @@ -265,6 +269,39 @@ static int acpi_fan_speed_cmp(const void *a, const void *b)
> return fps1->speed - fps2->speed;
> }
>
> +static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
> + int count;
> +
> + if (fps->control == 0xFFFFFFFF || fps->control > 100)
> + count = snprintf(buf, PAGE_SIZE, "not-defined:");
> + else
> + count = snprintf(buf, PAGE_SIZE, "%lld:", fps->control);
> +
> + if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
> + count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
> + else
> + count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->trip_point);
> +
> + if (fps->speed == 0xFFFFFFFF)
> + count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
> + else
> + count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->speed);
> +
> + if (fps->noise_level == 0xFFFFFFFF)
> + count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
> + else
> + count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->noise_level * 100);
> +
> + if (fps->power == 0xFFFFFFFF)
> + count += snprintf(&buf[count], PAGE_SIZE, "not-defined\n");
> + else
> + count += snprintf(&buf[count], PAGE_SIZE, "%lld\n", fps->power);
> +
> + return count;
> +}
> +
> static int acpi_fan_get_fps(struct acpi_device *device)
> {
> struct acpi_fan *fan = acpi_driver_data(device);
> @@ -295,12 +332,13 @@ static int acpi_fan_get_fps(struct acpi_device *device)
> }
> for (i = 0; i < fan->fps_count; i++) {
> struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
> - struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
> + struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
> + &fan->fps[i] };
> status = acpi_extract_package(&obj->package.elements[i + 1],
> &format, &fps);
> if (ACPI_FAILURE(status)) {
> dev_err(&device->dev, "Invalid _FPS element\n");
> - break;
> + goto err;
> }
> }
>
> @@ -308,6 +346,24 @@ static int acpi_fan_get_fps(struct acpi_device *device)
> sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
> acpi_fan_speed_cmp, NULL);
>
> + for (i = 0; i < fan->fps_count; ++i) {
> + struct acpi_fan_fps *fps = &fan->fps[i];
> +
> + snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
> + fps->dev_attr.show = show_state;
> + fps->dev_attr.store = NULL;
> + fps->dev_attr.attr.name = fps->name;
> + fps->dev_attr.attr.mode = 0444;
> + status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
> + if (status) {
> + int j;
> +
> + for (j = 0; j < i; ++j)
> + sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
> + break;
> + }
> + }
> +
> err:
> kfree(obj);
> return status;
> @@ -330,14 +386,20 @@ static int acpi_fan_probe(struct platform_device *pdev)
> platform_set_drvdata(pdev, fan);
>
> if (acpi_fan_is_acpi4(device)) {
> - if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
> - goto end;
> + result = acpi_fan_get_fif(device);
> + if (result)
> + return result;
> +
> + result = acpi_fan_get_fps(device);
> + if (result)
> + return result;
> +
> fan->acpi4 = true;
> } else {
> result = acpi_device_update_power(device, NULL);
> if (result) {
> dev_err(&device->dev, "Failed to set initial power state\n");
> - goto end;
> + goto err_end;
> }
> }
>
> @@ -350,7 +412,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
> &fan_cooling_ops);
> if (IS_ERR(cdev)) {
> result = PTR_ERR(cdev);
> - goto end;
> + goto err_end;
> }
>
> dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
> @@ -365,10 +427,21 @@ static int acpi_fan_probe(struct platform_device *pdev)
> result = sysfs_create_link(&cdev->device.kobj,
> &pdev->dev.kobj,
> "device");
> - if (result)
> + if (result) {
> dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
> + goto err_end;
> + }
> +
> + return 0;
> +
> +err_end:
> + if (fan->acpi4) {
> + int i;
> +
> + for (i = 0; i < fan->fps_count; ++i)
> + sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
> + }
>
> -end:
> return result;
> }
>
> @@ -376,6 +449,13 @@ static int acpi_fan_remove(struct platform_device *pdev)
> {
> struct acpi_fan *fan = platform_get_drvdata(pdev);
>
> + if (fan->acpi4) {
> + struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
> + int i;
> +
> + for (i = 0; i < fan->fps_count; ++i)
> + sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
> + }
> sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
> sysfs_remove_link(&fan->cdev->device.kobj, "device");
> thermal_cooling_device_unregister(fan->cdev);
> --
> 2.17.2
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2019-12-19 21:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-13 23:48 [PATCH v2 0/2] ACPI / Fan: Performance states Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 1/2] Documentation: ACPI: Documentation for Fan performance states Srinivas Pandruvada
2019-12-13 23:48 ` [PATCH v2 2/2] ACPI / fan: Display fan performance state information Srinivas Pandruvada
2019-12-19 21:38 ` Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).