162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Abstract code for CPUFreq governor tunable sysfs attributes.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016, Intel Corporation
662306a36Sopenharmony_ci * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "cpufreq_governor.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic inline struct governor_attr *to_gov_attr(struct attribute *attr)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	return container_of(attr, struct governor_attr, attr);
1462306a36Sopenharmony_ci}
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic ssize_t governor_show(struct kobject *kobj, struct attribute *attr,
1762306a36Sopenharmony_ci			     char *buf)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	struct governor_attr *gattr = to_gov_attr(attr);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	return gattr->show(to_gov_attr_set(kobj), buf);
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic ssize_t governor_store(struct kobject *kobj, struct attribute *attr,
2562306a36Sopenharmony_ci			      const char *buf, size_t count)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct gov_attr_set *attr_set = to_gov_attr_set(kobj);
2862306a36Sopenharmony_ci	struct governor_attr *gattr = to_gov_attr(attr);
2962306a36Sopenharmony_ci	int ret;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	mutex_lock(&attr_set->update_lock);
3262306a36Sopenharmony_ci	ret = attr_set->usage_count ? gattr->store(attr_set, buf, count) : -EBUSY;
3362306a36Sopenharmony_ci	mutex_unlock(&attr_set->update_lock);
3462306a36Sopenharmony_ci	return ret;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciconst struct sysfs_ops governor_sysfs_ops = {
3862306a36Sopenharmony_ci	.show	= governor_show,
3962306a36Sopenharmony_ci	.store	= governor_store,
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(governor_sysfs_ops);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_civoid gov_attr_set_init(struct gov_attr_set *attr_set, struct list_head *list_node)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	INIT_LIST_HEAD(&attr_set->policy_list);
4662306a36Sopenharmony_ci	mutex_init(&attr_set->update_lock);
4762306a36Sopenharmony_ci	attr_set->usage_count = 1;
4862306a36Sopenharmony_ci	list_add(list_node, &attr_set->policy_list);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gov_attr_set_init);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid gov_attr_set_get(struct gov_attr_set *attr_set, struct list_head *list_node)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	mutex_lock(&attr_set->update_lock);
5562306a36Sopenharmony_ci	attr_set->usage_count++;
5662306a36Sopenharmony_ci	list_add(list_node, &attr_set->policy_list);
5762306a36Sopenharmony_ci	mutex_unlock(&attr_set->update_lock);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gov_attr_set_get);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciunsigned int gov_attr_set_put(struct gov_attr_set *attr_set, struct list_head *list_node)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	unsigned int count;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	mutex_lock(&attr_set->update_lock);
6662306a36Sopenharmony_ci	list_del(list_node);
6762306a36Sopenharmony_ci	count = --attr_set->usage_count;
6862306a36Sopenharmony_ci	mutex_unlock(&attr_set->update_lock);
6962306a36Sopenharmony_ci	if (count)
7062306a36Sopenharmony_ci		return count;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	mutex_destroy(&attr_set->update_lock);
7362306a36Sopenharmony_ci	kobject_put(&attr_set->kobj);
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gov_attr_set_put);
77