Skip to content

Commit

Permalink
ACPI: platform_profile: Create class for ACPI platform profile
Browse files Browse the repository at this point in the history
When registering a platform profile handler create a class device
that will allow changing a single platform profile handler.

The class and sysfs group are no longer needed when the platform profile
core is a module and unloaded, so remove them at that time as well.

Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20241206031918.1537-11-mario.limonciello@amd.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
  • Loading branch information
Mario Limonciello authored and Ilpo Järvinen committed Dec 10, 2024
1 parent 1f3ac55 commit 77be5ca
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 5 deletions.
82 changes: 77 additions & 5 deletions drivers/acpi/platform_profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/mutex.h>
#include <linux/platform_profile.h>
#include <linux/sysfs.h>
Expand All @@ -22,6 +23,12 @@ static const char * const profile_names[] = {
};
static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST);

static DEFINE_IDA(platform_profile_ida);

static const struct class platform_profile_class = {
.name = "platform-profile",
};

static ssize_t platform_profile_choices_show(struct device *dev,
struct device_attribute *attr,
char *buf)
Expand Down Expand Up @@ -101,8 +108,21 @@ static struct attribute *platform_profile_attrs[] = {
NULL
};

static int profile_class_registered(struct device *dev, const void *data)
{
return 1;
}

static umode_t profile_class_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
{
if (!class_find_device(&platform_profile_class, NULL, NULL, profile_class_registered))
return 0;
return attr->mode;
}

static const struct attribute_group platform_profile_group = {
.attrs = platform_profile_attrs
.attrs = platform_profile_attrs,
.is_visible = profile_class_is_visible,
};

void platform_profile_notify(struct platform_profile_handler *pprof)
Expand Down Expand Up @@ -160,25 +180,77 @@ int platform_profile_register(struct platform_profile_handler *pprof)
if (cur_profile)
return -EEXIST;

err = sysfs_create_group(acpi_kobj, &platform_profile_group);
if (err)
return err;
/* create class interface for individual handler */
pprof->minor = ida_alloc(&platform_profile_ida, GFP_KERNEL);
if (pprof->minor < 0)
return pprof->minor;
pprof->class_dev = device_create(&platform_profile_class, pprof->dev,
MKDEV(0, 0), pprof, "platform-profile-%d",
pprof->minor);
if (IS_ERR(pprof->class_dev)) {
err = PTR_ERR(pprof->class_dev);
goto cleanup_ida;
}

cur_profile = pprof;

err = sysfs_update_group(acpi_kobj, &platform_profile_group);
if (err)
goto cleanup_cur;

return 0;

cleanup_cur:
cur_profile = NULL;
device_unregister(pprof->class_dev);

cleanup_ida:
ida_free(&platform_profile_ida, pprof->minor);

return err;
}
EXPORT_SYMBOL_GPL(platform_profile_register);

int platform_profile_remove(struct platform_profile_handler *pprof)
{
int id;
guard(mutex)(&profile_lock);

sysfs_remove_group(acpi_kobj, &platform_profile_group);
cur_profile = NULL;

id = pprof->minor;
device_unregister(pprof->class_dev);
ida_free(&platform_profile_ida, id);

sysfs_update_group(acpi_kobj, &platform_profile_group);

return 0;
}
EXPORT_SYMBOL_GPL(platform_profile_remove);

static int __init platform_profile_init(void)
{
int err;

err = class_register(&platform_profile_class);
if (err)
return err;

err = sysfs_create_group(acpi_kobj, &platform_profile_group);
if (err)
class_unregister(&platform_profile_class);

return err;
}

static void __exit platform_profile_exit(void)
{
sysfs_remove_group(acpi_kobj, &platform_profile_group);
class_unregister(&platform_profile_class);
}
module_init(platform_profile_init);
module_exit(platform_profile_exit);

MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
MODULE_DESCRIPTION("ACPI platform profile sysfs interface");
MODULE_LICENSE("GPL");
2 changes: 2 additions & 0 deletions include/linux/platform_profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ enum platform_profile_option {
struct platform_profile_handler {
const char *name;
struct device *dev;
struct device *class_dev;
int minor;
unsigned long choices[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)];
int (*profile_get)(struct platform_profile_handler *pprof,
enum platform_profile_option *profile);
Expand Down

0 comments on commit 77be5ca

Please sign in to comment.