1b903737bSHaren Myneni // SPDX-License-Identifier: GPL-2.0-or-later
2b903737bSHaren Myneni /*
3b903737bSHaren Myneni * Copyright 2022-23 IBM Corp.
4b903737bSHaren Myneni */
5b903737bSHaren Myneni
6b903737bSHaren Myneni #define pr_fmt(fmt) "vas: " fmt
7b903737bSHaren Myneni
8b903737bSHaren Myneni #include <linux/module.h>
9b903737bSHaren Myneni #include <linux/kernel.h>
10b903737bSHaren Myneni #include <linux/miscdevice.h>
11b903737bSHaren Myneni #include <linux/kobject.h>
12b903737bSHaren Myneni #include <linux/slab.h>
13b903737bSHaren Myneni #include <linux/mm.h>
14b903737bSHaren Myneni
15b903737bSHaren Myneni #include "vas.h"
16b903737bSHaren Myneni
17b903737bSHaren Myneni #ifdef CONFIG_SYSFS
18b903737bSHaren Myneni static struct kobject *pseries_vas_kobj;
19b903737bSHaren Myneni static struct kobject *gzip_caps_kobj;
20b903737bSHaren Myneni
21b903737bSHaren Myneni struct vas_caps_entry {
22b903737bSHaren Myneni struct kobject kobj;
23b903737bSHaren Myneni struct vas_cop_feat_caps *caps;
24b903737bSHaren Myneni };
25b903737bSHaren Myneni
26b903737bSHaren Myneni #define to_caps_entry(entry) container_of(entry, struct vas_caps_entry, kobj)
27b903737bSHaren Myneni
2845f06eacSHaren Myneni /*
2945f06eacSHaren Myneni * This function is used to get the notification from the drmgr when
3057831bfbSHaren Myneni * QoS credits are changed.
3145f06eacSHaren Myneni */
update_total_credits_store(struct vas_cop_feat_caps * caps,const char * buf,size_t count)3257831bfbSHaren Myneni static ssize_t update_total_credits_store(struct vas_cop_feat_caps *caps,
3345f06eacSHaren Myneni const char *buf, size_t count)
3445f06eacSHaren Myneni {
3545f06eacSHaren Myneni int err;
3645f06eacSHaren Myneni u16 creds;
3745f06eacSHaren Myneni
3845f06eacSHaren Myneni err = kstrtou16(buf, 0, &creds);
3957831bfbSHaren Myneni /*
4057831bfbSHaren Myneni * The user space interface from the management console
4157831bfbSHaren Myneni * notifies OS with the new QoS credits and then the
4257831bfbSHaren Myneni * hypervisor. So OS has to use this new credits value
4357831bfbSHaren Myneni * and reconfigure VAS windows (close or reopen depends
4457831bfbSHaren Myneni * on the credits available) instead of depending on VAS
4557831bfbSHaren Myneni * QoS capabilities from the hypervisor.
4657831bfbSHaren Myneni */
4745f06eacSHaren Myneni if (!err)
4857831bfbSHaren Myneni err = vas_reconfig_capabilties(caps->win_type, creds);
4945f06eacSHaren Myneni
5045f06eacSHaren Myneni if (err)
5145f06eacSHaren Myneni return -EINVAL;
5245f06eacSHaren Myneni
5357831bfbSHaren Myneni pr_info("Set QoS total credits %u\n", creds);
5457831bfbSHaren Myneni
5545f06eacSHaren Myneni return count;
5645f06eacSHaren Myneni }
5745f06eacSHaren Myneni
58b903737bSHaren Myneni #define sysfs_caps_entry_read(_name) \
59b903737bSHaren Myneni static ssize_t _name##_show(struct vas_cop_feat_caps *caps, char *buf) \
60b903737bSHaren Myneni { \
61b903737bSHaren Myneni return sprintf(buf, "%d\n", atomic_read(&caps->_name)); \
62b903737bSHaren Myneni }
63b903737bSHaren Myneni
64b903737bSHaren Myneni struct vas_sysfs_entry {
65b903737bSHaren Myneni struct attribute attr;
66b903737bSHaren Myneni ssize_t (*show)(struct vas_cop_feat_caps *, char *);
67b903737bSHaren Myneni ssize_t (*store)(struct vas_cop_feat_caps *, const char *, size_t);
68b903737bSHaren Myneni };
69b903737bSHaren Myneni
70b903737bSHaren Myneni #define VAS_ATTR_RO(_name) \
71b903737bSHaren Myneni sysfs_caps_entry_read(_name); \
72b903737bSHaren Myneni static struct vas_sysfs_entry _name##_attribute = __ATTR(_name, \
73b903737bSHaren Myneni 0444, _name##_show, NULL);
74b903737bSHaren Myneni
75b903737bSHaren Myneni /*
76b903737bSHaren Myneni * Create sysfs interface:
77657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities
78b903737bSHaren Myneni * This directory contains the following VAS GZIP capabilities
791fd02f66SJulia Lawall * for the default credit type.
80657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities/nr_total_credits
81b903737bSHaren Myneni * Total number of default credits assigned to the LPAR which
82b903737bSHaren Myneni * can be changed with DLPAR operation.
83657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities/nr_used_credits
84b903737bSHaren Myneni * Number of credits used by the user space. One credit will
85b903737bSHaren Myneni * be assigned for each window open.
86b903737bSHaren Myneni *
87657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities
88b903737bSHaren Myneni * This directory contains the following VAS GZIP capabilities
89b903737bSHaren Myneni * for the Quality of Service (QoS) credit type.
90657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/nr_total_credits
91b903737bSHaren Myneni * Total number of QoS credits assigned to the LPAR. The user
92b903737bSHaren Myneni * has to define this value using HMC interface. It can be
93b903737bSHaren Myneni * changed dynamically by the user.
94657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/nr_used_credits
95b903737bSHaren Myneni * Number of credits used by the user space.
96657ac633SHaren Myneni * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/update_total_credits
9745f06eacSHaren Myneni * Update total QoS credits dynamically
98b903737bSHaren Myneni */
99b903737bSHaren Myneni
100b903737bSHaren Myneni VAS_ATTR_RO(nr_total_credits);
101b903737bSHaren Myneni VAS_ATTR_RO(nr_used_credits);
102b903737bSHaren Myneni
10345f06eacSHaren Myneni static struct vas_sysfs_entry update_total_credits_attribute =
10457831bfbSHaren Myneni __ATTR(update_total_credits, 0200, NULL, update_total_credits_store);
10545f06eacSHaren Myneni
10645f06eacSHaren Myneni static struct attribute *vas_def_capab_attrs[] = {
107b903737bSHaren Myneni &nr_total_credits_attribute.attr,
108b903737bSHaren Myneni &nr_used_credits_attribute.attr,
109b903737bSHaren Myneni NULL,
110b903737bSHaren Myneni };
111c31bc046SGreg Kroah-Hartman ATTRIBUTE_GROUPS(vas_def_capab);
112b903737bSHaren Myneni
11345f06eacSHaren Myneni static struct attribute *vas_qos_capab_attrs[] = {
11445f06eacSHaren Myneni &nr_total_credits_attribute.attr,
11545f06eacSHaren Myneni &nr_used_credits_attribute.attr,
11645f06eacSHaren Myneni &update_total_credits_attribute.attr,
11745f06eacSHaren Myneni NULL,
11845f06eacSHaren Myneni };
119c31bc046SGreg Kroah-Hartman ATTRIBUTE_GROUPS(vas_qos_capab);
12045f06eacSHaren Myneni
vas_type_show(struct kobject * kobj,struct attribute * attr,char * buf)121b903737bSHaren Myneni static ssize_t vas_type_show(struct kobject *kobj, struct attribute *attr,
122b903737bSHaren Myneni char *buf)
123b903737bSHaren Myneni {
124b903737bSHaren Myneni struct vas_caps_entry *centry;
125b903737bSHaren Myneni struct vas_cop_feat_caps *caps;
126b903737bSHaren Myneni struct vas_sysfs_entry *entry;
127b903737bSHaren Myneni
128b903737bSHaren Myneni centry = to_caps_entry(kobj);
129b903737bSHaren Myneni caps = centry->caps;
130b903737bSHaren Myneni entry = container_of(attr, struct vas_sysfs_entry, attr);
131b903737bSHaren Myneni
132b903737bSHaren Myneni if (!entry->show)
133b903737bSHaren Myneni return -EIO;
134b903737bSHaren Myneni
135b903737bSHaren Myneni return entry->show(caps, buf);
136b903737bSHaren Myneni }
137b903737bSHaren Myneni
vas_type_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)138b903737bSHaren Myneni static ssize_t vas_type_store(struct kobject *kobj, struct attribute *attr,
139b903737bSHaren Myneni const char *buf, size_t count)
140b903737bSHaren Myneni {
141b903737bSHaren Myneni struct vas_caps_entry *centry;
142b903737bSHaren Myneni struct vas_cop_feat_caps *caps;
143b903737bSHaren Myneni struct vas_sysfs_entry *entry;
144b903737bSHaren Myneni
145b903737bSHaren Myneni centry = to_caps_entry(kobj);
146b903737bSHaren Myneni caps = centry->caps;
147b903737bSHaren Myneni entry = container_of(attr, struct vas_sysfs_entry, attr);
148b903737bSHaren Myneni if (!entry->store)
149b903737bSHaren Myneni return -EIO;
150b903737bSHaren Myneni
151b903737bSHaren Myneni return entry->store(caps, buf, count);
152b903737bSHaren Myneni }
153b903737bSHaren Myneni
vas_type_release(struct kobject * kobj)154b903737bSHaren Myneni static void vas_type_release(struct kobject *kobj)
155b903737bSHaren Myneni {
156b903737bSHaren Myneni struct vas_caps_entry *centry = to_caps_entry(kobj);
157b903737bSHaren Myneni kfree(centry);
158b903737bSHaren Myneni }
159b903737bSHaren Myneni
160b903737bSHaren Myneni static const struct sysfs_ops vas_sysfs_ops = {
161b903737bSHaren Myneni .show = vas_type_show,
162b903737bSHaren Myneni .store = vas_type_store,
163b903737bSHaren Myneni };
164b903737bSHaren Myneni
16545f06eacSHaren Myneni static struct kobj_type vas_def_attr_type = {
166b903737bSHaren Myneni .release = vas_type_release,
167b903737bSHaren Myneni .sysfs_ops = &vas_sysfs_ops,
168c31bc046SGreg Kroah-Hartman .default_groups = vas_def_capab_groups,
169b903737bSHaren Myneni };
170b903737bSHaren Myneni
17145f06eacSHaren Myneni static struct kobj_type vas_qos_attr_type = {
17245f06eacSHaren Myneni .release = vas_type_release,
17345f06eacSHaren Myneni .sysfs_ops = &vas_sysfs_ops,
174c31bc046SGreg Kroah-Hartman .default_groups = vas_qos_capab_groups,
17545f06eacSHaren Myneni };
17645f06eacSHaren Myneni
vas_caps_kobj_name(struct vas_caps_entry * centry,struct kobject ** kobj)17745f06eacSHaren Myneni static char *vas_caps_kobj_name(struct vas_caps_entry *centry,
178b903737bSHaren Myneni struct kobject **kobj)
179b903737bSHaren Myneni {
18045f06eacSHaren Myneni struct vas_cop_feat_caps *caps = centry->caps;
18145f06eacSHaren Myneni
182b903737bSHaren Myneni if (caps->descriptor == VAS_GZIP_QOS_CAPABILITIES) {
18345f06eacSHaren Myneni kobject_init(¢ry->kobj, &vas_qos_attr_type);
184b903737bSHaren Myneni *kobj = gzip_caps_kobj;
185b903737bSHaren Myneni return "qos_capabilities";
186b903737bSHaren Myneni } else if (caps->descriptor == VAS_GZIP_DEFAULT_CAPABILITIES) {
18745f06eacSHaren Myneni kobject_init(¢ry->kobj, &vas_def_attr_type);
188b903737bSHaren Myneni *kobj = gzip_caps_kobj;
189b903737bSHaren Myneni return "default_capabilities";
190b903737bSHaren Myneni } else
191b903737bSHaren Myneni return "Unknown";
192b903737bSHaren Myneni }
193b903737bSHaren Myneni
194b903737bSHaren Myneni /*
195b903737bSHaren Myneni * Add feature specific capability dir entry.
196b903737bSHaren Myneni * Ex: VDefGzip or VQosGzip
197b903737bSHaren Myneni */
sysfs_add_vas_caps(struct vas_cop_feat_caps * caps)198b903737bSHaren Myneni int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps)
199b903737bSHaren Myneni {
200b903737bSHaren Myneni struct vas_caps_entry *centry;
201b903737bSHaren Myneni struct kobject *kobj = NULL;
202b903737bSHaren Myneni int ret = 0;
203b903737bSHaren Myneni char *name;
204b903737bSHaren Myneni
205b903737bSHaren Myneni centry = kzalloc(sizeof(*centry), GFP_KERNEL);
206b903737bSHaren Myneni if (!centry)
207b903737bSHaren Myneni return -ENOMEM;
208b903737bSHaren Myneni
209b903737bSHaren Myneni centry->caps = caps;
21045f06eacSHaren Myneni name = vas_caps_kobj_name(centry, &kobj);
211b903737bSHaren Myneni
212b903737bSHaren Myneni if (kobj) {
213b903737bSHaren Myneni ret = kobject_add(¢ry->kobj, kobj, "%s", name);
214b903737bSHaren Myneni
215b903737bSHaren Myneni if (ret) {
216b903737bSHaren Myneni pr_err("VAS: sysfs kobject add / event failed %d\n",
217b903737bSHaren Myneni ret);
218b903737bSHaren Myneni kobject_put(¢ry->kobj);
219b903737bSHaren Myneni }
220b903737bSHaren Myneni }
221b903737bSHaren Myneni
222b903737bSHaren Myneni return ret;
223b903737bSHaren Myneni }
224b903737bSHaren Myneni
225b903737bSHaren Myneni static struct miscdevice vas_miscdev = {
226b903737bSHaren Myneni .minor = MISC_DYNAMIC_MINOR,
227b903737bSHaren Myneni .name = "vas",
228b903737bSHaren Myneni };
229b903737bSHaren Myneni
230b903737bSHaren Myneni /*
231b903737bSHaren Myneni * Add VAS and VasCaps (overall capabilities) dir entries.
232b903737bSHaren Myneni */
sysfs_pseries_vas_init(struct vas_all_caps * vas_caps)233b903737bSHaren Myneni int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps)
234b903737bSHaren Myneni {
235b903737bSHaren Myneni int ret;
236b903737bSHaren Myneni
237b903737bSHaren Myneni ret = misc_register(&vas_miscdev);
238b903737bSHaren Myneni if (ret < 0) {
239b903737bSHaren Myneni pr_err("%s: register vas misc device failed\n", __func__);
240b903737bSHaren Myneni return ret;
241b903737bSHaren Myneni }
242b903737bSHaren Myneni
243b903737bSHaren Myneni /*
244b903737bSHaren Myneni * The hypervisor does not expose multiple VAS instances, but can
245b903737bSHaren Myneni * see multiple VAS instances on PowerNV. So create 'vas0' directory
246b903737bSHaren Myneni * on pseries.
247b903737bSHaren Myneni */
248b903737bSHaren Myneni pseries_vas_kobj = kobject_create_and_add("vas0",
249b903737bSHaren Myneni &vas_miscdev.this_device->kobj);
250b903737bSHaren Myneni if (!pseries_vas_kobj) {
251*426e5805SZheng Bin misc_deregister(&vas_miscdev);
252b903737bSHaren Myneni pr_err("Failed to create VAS sysfs entry\n");
253b903737bSHaren Myneni return -ENOMEM;
254b903737bSHaren Myneni }
255b903737bSHaren Myneni
256b903737bSHaren Myneni if ((vas_caps->feat_type & VAS_GZIP_QOS_FEAT_BIT) ||
257b903737bSHaren Myneni (vas_caps->feat_type & VAS_GZIP_DEF_FEAT_BIT)) {
258b903737bSHaren Myneni gzip_caps_kobj = kobject_create_and_add("gzip",
259b903737bSHaren Myneni pseries_vas_kobj);
260b903737bSHaren Myneni if (!gzip_caps_kobj) {
261b903737bSHaren Myneni pr_err("Failed to create VAS GZIP capability entry\n");
262b903737bSHaren Myneni kobject_put(pseries_vas_kobj);
263*426e5805SZheng Bin misc_deregister(&vas_miscdev);
264b903737bSHaren Myneni return -ENOMEM;
265b903737bSHaren Myneni }
266b903737bSHaren Myneni }
267b903737bSHaren Myneni
268b903737bSHaren Myneni return 0;
269b903737bSHaren Myneni }
270b903737bSHaren Myneni
271b903737bSHaren Myneni #else
sysfs_add_vas_caps(struct vas_cop_feat_caps * caps)272b903737bSHaren Myneni int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps)
273b903737bSHaren Myneni {
274b903737bSHaren Myneni return 0;
275b903737bSHaren Myneni }
276b903737bSHaren Myneni
sysfs_pseries_vas_init(struct vas_all_caps * vas_caps)277b903737bSHaren Myneni int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps)
278b903737bSHaren Myneni {
279b903737bSHaren Myneni return 0;
280b903737bSHaren Myneni }
281b903737bSHaren Myneni #endif
282