On Sun, 1 Dec 2024, Mario Limonciello wrote: > Reading and writing the `profile` sysfs file will use the callbacks for > the platform profile handler to read or set the given profile. > > Tested-by: Mark Pearson <mpearson-lenovo@xxxxxxxxx> > Reviewed-by: Mark Pearson <mpearson-lenovo@xxxxxxxxx> > Reviewed-by: Armin Wolf <W_Armin@xxxxxx> > Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> -- i. > --- > v8: > * whitespace > * rename variables > --- > drivers/acpi/platform_profile.c | 102 ++++++++++++++++++++++++++++++++ > 1 file changed, 102 insertions(+) > > diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c > index 885f41bca6c25..fdff374aab128 100644 > --- a/drivers/acpi/platform_profile.c > +++ b/drivers/acpi/platform_profile.c > @@ -47,6 +47,52 @@ static ssize_t _commmon_choices_show(unsigned long *choices, char *buf) > return len; > } > > +/** > + * _store_class_profile - Set the profile for a class device > + * @dev: The class device > + * @data: The profile to set > + */ > +static int _store_class_profile(struct device *dev, void *data) > +{ > + struct platform_profile_handler *handler; > + int *bit = (int *)data; > + > + lockdep_assert_held(&profile_lock); > + handler = dev_get_drvdata(dev); > + if (!test_bit(*bit, handler->choices)) > + return -EOPNOTSUPP; > + > + return handler->profile_set(handler, *bit); > +} > + > +/** > + * get_class_profile - Show the current profile for a class device > + * @dev: The class device > + * @profile: The profile to return > + * Return: 0 on success, -errno on failure > + */ > +static int get_class_profile(struct device *dev, > + enum platform_profile_option *profile) > +{ > + struct platform_profile_handler *handler; > + enum platform_profile_option val; > + int err; > + > + lockdep_assert_held(&profile_lock); > + handler = dev_get_drvdata(dev); > + err = handler->profile_get(handler, &val); > + if (err) { > + pr_err("Failed to get profile for handler %s\n", handler->name); > + return err; > + } > + > + if (WARN_ON(val >= PLATFORM_PROFILE_LAST)) > + return -EINVAL; > + *profile = val; > + > + return 0; > +} > + > /** > * name_show - Show the name of the profile handler > * @dev: The device > @@ -81,9 +127,65 @@ static ssize_t choices_show(struct device *dev, > } > static DEVICE_ATTR_RO(choices); > > +/** > + * profile_show - Show the current profile for a class device > + * @dev: The device > + * @attr: The attribute > + * @buf: The buffer to write to > + * > + * Return: The number of bytes written > + */ > +static ssize_t profile_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + enum platform_profile_option profile = PLATFORM_PROFILE_LAST; > + int err; > + > + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { > + err = get_class_profile(dev, &profile); > + if (err) > + return err; > + } > + > + return sysfs_emit(buf, "%s\n", profile_names[profile]); > +} > + > +/** > + * profile_store - Set the profile for a class device > + * @dev: The device > + * @attr: The attribute > + * @buf: The buffer to read from > + * @count: The number of bytes to read > + * > + * Return: The number of bytes read > + */ > +static ssize_t profile_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int index, ret; > + > + index = sysfs_match_string(profile_names, buf); > + if (index < 0) > + return -EINVAL; > + > + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { > + ret = _store_class_profile(dev, &index); > + if (ret) > + return ret; > + } > + > + sysfs_notify(acpi_kobj, NULL, "platform_profile"); > + > + return count; > +} > +static DEVICE_ATTR_RW(profile); > + > static struct attribute *profile_attrs[] = { > &dev_attr_name.attr, > &dev_attr_choices.attr, > + &dev_attr_profile.attr, > NULL > }; > ATTRIBUTE_GROUPS(profile); >