From: Mark Pearson <markpearson@lenovo.com>
To: "Barnabás Pőcze" <pobrn@protonmail.com>
Cc: "rjw@rjwysocki.net" <rjw@rjwysocki.net>,
"hdegoede@redhat.com" <hdegoede@redhat.com>,
"mgross@linux.intel.com" <mgross@linux.intel.com>,
"linux-acpi@vger.kernel.org" <linux-acpi@vger.kernel.org>,
"mario.limonciello@dell.com" <mario.limonciello@dell.com>,
"eliadevito@gmail.com" <eliadevito@gmail.com>,
"hadess@hadess.net" <hadess@hadess.net>,
"bberg@redhat.com" <bberg@redhat.com>,
"platform-driver-x86@vger.kernel.org"
<platform-driver-x86@vger.kernel.org>,
"dvhart@infradead.org" <dvhart@infradead.org>
Subject: Re: [External] Re: [PATCH 2/3] ACPI: platform-profile: Add platform profile support
Date: Tue, 10 Nov 2020 09:32:38 -0500 [thread overview]
Message-ID: <72b0fb0a-8007-d795-8b1a-68fa58231c23@lenovo.com> (raw)
In-Reply-To: <2gY5rkKaKLKayk0DYW0lvZ_aIAs8vSf9FOy2obdGvph_7XcpyHlkafBTpW8RHKC5nEcEz_eY-s4pJtuR2ebltW2Fu10GRssTmMxKMuS4PU8=@protonmail.com>
Thanks Barnabas
On 10/11/2020 05:15, Barnabás Pőcze wrote:
> Hi
>
> I've added some questions and comments inline.
>
>
>
> 2020. november 10., kedd 4:31 keltezéssel, Mark Pearson írta:
>
>> [...]
>> diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c
>> new file mode 100644
>> index 000000000000..3c460c0a3857
>> --- /dev/null
>> +++ b/drivers/acpi/platform_profile.c
>> @@ -0,0 +1,172 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +/*
>> + * platform_profile.c - Platform profile sysfs interface
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/printk.h>
>> +#include <linux/kobject.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/init.h>
>> +#include <linux/fs.h>
>> +#include <linux/string.h>
>> +#include <linux/device.h>
>> +#include <linux/acpi.h>
>> +#include <linux/mutex.h>
>> +#include <acpi/acpi_bus.h>
>> +#include <linux/platform_profile.h>
>
> This should preferably be alphabetically sorted.
Ack - I hadn't realised that was a requirement. I'll update
>
>
>> +
>> +struct platform_profile *cur_profile;
>
> This should be `static`.
Agreed.
>
>
>> +DEFINE_MUTEX(profile_lock);
>> +
>> +/* Ensure the first char of each profile is unique */
>
> I wholeheartedly disagree that only the first character should be considered.
> It is not future-proof, potentially subverts user expectation, and even worse,
> someone could rely on this (undocumented) behaviour.
OK, fair enough. I debated about it and it's nice just to do
echo 'L' > platform_profile
instead of typing in a whole string, but I appreciate it's lazy.
I'm OK with fixing based on your points.
>
>
>> +static char *profile_str[] = {
>
> Why is it not `const`?
My mistake. I will fix
>
>
>> + "Low-power",
>> + "Cool",
>> + "Quiet",
>> + "Balance",
>> + "Performance",
>> + "Unknown"
>
> "unknown" is not documented, yet it may be returned to userspace.
Ack - I'll look into if it's really needed, but it seemed sensible to
have it whilst doing the implementation.
>
>
>> +};
>
> The documentation has the names in all-lowercase, and in my opinion it'd be
> better to use lowercase names here as well.
Agreed - my bad. I'll fix.
>
>
>> +
>> +static ssize_t platform_profile_choices_show(struct device *dev,
>> + struct device_attribute *attr,
>> + char *buf)
>> +{
>> + int i;
>> + int ret, count = 0;
>> +
>> + mutex_lock(&profile_lock);
>> + if (!cur_profile) {
>> + mutex_unlock(&profile_lock);
>> + return -ENODEV;
>> + }
>> +
>> + if (!cur_profile->choices) {
>> + mutex_unlock(&profile_lock);
>> + return snprintf(buf, PAGE_SIZE, "None");
>
> "None" is not documented anywhere as far as I can see, maybe an empty line
> would be better in this case?
Agreed, I'll fix.
>
>
>> + }
>> +
>> + for (i = profile_low; i < profile_unknown; i++) {
>> + if (cur_profile->choices & (1 << i)) {
>
> `BIT(i)`?
Yes, that would be better.
>
>
>> + ret = snprintf(buf+count, PAGE_SIZE, "%s ", profile_str[i]);
>
> You could use `sysfs_emit_at()`. `ret` is only used in this block, so it could be
> defined here.
OK - I hadn't come across that function. I'll update to use it.
>
>
>> + if (ret < 0)
>> + break;
>
> However unlikely this case is, I'm not sure if providing partial values is
> better than not providing any data at all.
Interesting point, I think I agree.
I'll look at returning an empty string if an error occurs.
>
>
>> + count += ret;
>> + }
>> + }
>> + mutex_unlock(&profile_lock);
>
> I think a newline character should be written at the end (possibly overwriting
> the last space).
OK.
>
>
>> + return count;
>> +}
>> +
>> +static ssize_t platform_profile_show(struct device *dev,
>> + struct device_attribute *attr,
>> + char *buf)
>> +{
>> + enum profile_option profile = profile_unknown;
>> +
>> + mutex_lock(&profile_lock);
>> + if (!cur_profile) {
>> + mutex_unlock(&profile_lock);
>> + return -ENODEV;
>> + }
>> + if (cur_profile->profile_get)
>> + profile = cur_profile->profile_get();
>
> I'd assume that `profile_get()` can return any arbitrary errno, which is then
> propagated to the "reader", but it seems that's not the case?
> I think returning `-EOPNOTSUPP` would be better if `profile_get` is NULL.
OK - I went through a few iterations here and it's a bit weak. I'll look
at it again.
>
>
>> + mutex_unlock(&profile_lock);
>> +
>> + return snprintf(buf, PAGE_SIZE, "%s", profile_str[profile]);
>
> There is `sysfs_emit()`, as far as I know it is supposed to replace this exact
> snprintf(...) idiom. Directly indexing the `profile_str` with an unchecked
> value here is rather unsafe in my opinion.
Agreed - I'll fix this.
>
>
>> +}
>> +
>> +static ssize_t platform_profile_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + enum profile_option profile;
>> +
>> + mutex_lock(&profile_lock);
>> + if (!cur_profile) {
>> + mutex_unlock(&profile_lock);
>> + return -ENODEV;
>> + }
>> +
>> + /* Scan for a matching profile */
>> + for (profile = profile_low; profile < profile_unknown; profile++) {
>> + if (toupper(buf[0]) == profile_str[profile][0])
>> + break;
>> + }
>> + if (profile == profile_unknown) {
>> + mutex_unlock(&profile_lock);
>> + return -EINVAL;
>> + }
>> +
>> + if (cur_profile->profile_set)
>> + cur_profile->profile_set(profile);
>
> The return value is entirely discarded? I'd assume it's returned to the "writer".
> I'm also not sure if ignoring if `profile_set` is NULL is the best course of
> action. Maybe returning `-EOPNOTSUPP` would be better?
OK.
>
>
>> +
>> + mutex_unlock(&profile_lock);
>> + return count;
>> +}
>> +
>> +static DEVICE_ATTR_RO(platform_profile_choices);
>> +static DEVICE_ATTR_RW(platform_profile);
>> +
>> +static struct attribute *platform_profile_attributes[] = {
>> + &dev_attr_platform_profile_choices.attr,
>> + &dev_attr_platform_profile.attr,
>> + NULL,
>> +};
>> +
>> +static const struct attribute_group platform_profile_attr_group = {
>> + .attrs = platform_profile_attributes,
>> +};
>
> It's a minor thing, but there is an `ATTRIBUTE_GROUPS()` macro which could possibly
> simplify the above part.
OK - I'd not come across that and will look at using it.
>
>
>> +
>> +int platform_profile_notify(void)
>> +{
>> + if (!cur_profile)
>> + return -ENODEV;
>> + sysfs_notify(acpi_kobj, NULL, "platform_profile");
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(platform_profile_notify);
>> +
>> +int platform_profile_register(struct platform_profile *pprof)
>> +{
>> + mutex_lock(&profile_lock);
>> + /* We can only have one active profile */
>> + if (cur_profile) {
>> + mutex_unlock(&profile_lock);
>> + return -EEXIST;
>> + }
>> + cur_profile = pprof;
>> + mutex_unlock(&profile_lock);
>> + return sysfs_create_group(acpi_kobj, &platform_profile_attr_group);
>> +}
>> +EXPORT_SYMBOL_GPL(platform_profile_register);
>> +
>> +int platform_profile_unregister(void)
>> +{
>> + mutex_lock(&profile_lock);
>> + sysfs_remove_group(acpi_kobj, &platform_profile_attr_group);
>> + cur_profile = NULL;
>> + mutex_unlock(&profile_lock);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(platform_profile_unregister);
>> +
>> +static int __init platform_profile_init(void)
>> +{
>> + cur_profile = NULL;
>
> If I'm not missing anything, `cur_profile` will be initialized to NULL, thus
> this is not needed.
I guess I was just playing safe here, I think you're right.
I'll remove.
>
>
>> + return 0;
>> +}
>> +
>> +static void platform_profile_exit(void)
>
> This should be marked `__exit`.
Not sure how I missed that one.... Thanks.
>
>
>> +{
>> + sysfs_remove_group(acpi_kobj, &platform_profile_attr_group);
>> + cur_profile = NULL;
>> +}
>> +
>> +MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
>> +MODULE_LICENSE("GPL");
>> +
>> +module_init(platform_profile_init);
>> +module_exit(platform_profile_exit);
>> diff --git a/include/linux/platform_profile.h b/include/linux/platform_profile.h
>> new file mode 100644
>> index 000000000000..347a12172c09
>> --- /dev/null
>> +++ b/include/linux/platform_profile.h
>> @@ -0,0 +1,36 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * platform_profile.h - platform profile sysfs interface
>> + *
>> + * See Documentation/ABI/testing/sysfs-platform_profile for more information.
>> + */
>> +
>> +#ifndef _PLATFORM_PROFILE_H_
>> +#define _PLATFORM_PROFILE_H_
>> +
>> +/*
>> + * If more options are added please update profile_str
>> + * array in platform-profile.c
>> + */
>> +
>> +enum profile_option {
>> + profile_low,
>> + profile_cool,
>> + profile_quiet,
>> + profile_balance,
>> + profile_perform,
>> + profile_unknown /* Must always be last */
>> +};
>
> Shouldn't these be prefixed by `platform_`? And I think it'd be better to have
> `profile_unknown` as the first value in the enumeration.
I can add 'platform_'
I liked having profile_unknown as the last value as it makes scanning
from 'low' to 'unknown' more future proof if other profiles get added
(e.g in platform_profile_choices_show).
Is this something you feel strongly about?
>
>
>> +
>> +struct platform_profile {
>
> Personally, I think a name like platform_profile_(handler|provider)
> would be a better fit.
OK - happy to update that.
>
>
>> + unsigned int choices; /* bitmap of available choices */
>
> Most comments are capitalized.
Ack.
>
>
>> + int cur_profile; /* Current active profile */
>
> `cur_profile` field doesn't seem to be used here. I see that it's utilized in the
> thinkpad_acpi driver, but I feel like this does not "belong" here.
It seemed a logical place to keep it to me. I understand where you're
coming from, and I can change it so it's just internal to
thinkpad_acpi.c but it just seemed a nice place to keep it and I'm
guessing other implementations would like to have it too.
I'd be interested to see what others have to say on this one.
>
>
>> + int (*profile_get)(void);
>> + int (*profile_set)(int profile);
>
> Why does it take an `int` instead of `enum profile_option`?
Mostly for error conditions to be propagated if needs be, though I have
some improvements to do based on the comments above :)
>
>
>> +};
>> +
>> +extern int platform_profile_register(struct platform_profile *pprof);
>> +extern int platform_profile_unregister(void);
>> +extern int platform_profile_notify(void);
>> +
>
> `extern` could be omitted from here. Although it seems rather "unregulated"
> whether `extern` is to be present in header files or not.
OK.
>
>
>> +#endif /*_PLATFORM_PROFILE_H_*/
>> --
>> 2.28.0
>
>
> Regards,
> Barnabás Pőcze
>
Thank you for the detailed review - really appreciate the time you spent
going through this.
Mark
next prev parent reply other threads:[~2020-11-10 14:40 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-10 3:31 [PATCH 0/3] Platform Profile support Mark Pearson
2020-11-10 3:31 ` [PATCH 1/3] Documentation: Add documentation for new platform_profile sysfs attribute Mark Pearson
2020-11-10 10:03 ` Andy Shevchenko
2020-11-10 14:09 ` [External] " Mark Pearson
2020-11-10 3:31 ` [PATCH 2/3] ACPI: platform-profile: Add platform profile support Mark Pearson
2020-11-10 10:15 ` Barnabás Pőcze
2020-11-10 14:32 ` Mark Pearson [this message]
2020-11-10 23:48 ` [External] " Barnabás Pőcze
2020-11-11 10:29 ` Hans de Goede
2020-11-10 10:26 ` Andy Shevchenko
2020-11-10 14:39 ` [External] " Mark Pearson
2020-11-10 12:53 ` Rafael J. Wysocki
2020-11-10 14:40 ` [External] " Mark Pearson
2020-11-10 3:31 ` [PATCH 3/3] platform/x86: thinkpad_acpi: " Mark Pearson
2020-11-10 10:06 ` Andy Shevchenko
2020-11-10 14:41 ` [External] " Mark Pearson
2020-11-19 16:37 ` [PATCH 0/3] Platform Profile support Bastien Nocera
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=72b0fb0a-8007-d795-8b1a-68fa58231c23@lenovo.com \
--to=markpearson@lenovo.com \
--cc=bberg@redhat.com \
--cc=dvhart@infradead.org \
--cc=eliadevito@gmail.com \
--cc=hadess@hadess.net \
--cc=hdegoede@redhat.com \
--cc=linux-acpi@vger.kernel.org \
--cc=mario.limonciello@dell.com \
--cc=mgross@linux.intel.com \
--cc=platform-driver-x86@vger.kernel.org \
--cc=pobrn@protonmail.com \
--cc=rjw@rjwysocki.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).