Excerpts from Haren Myneni's message of February 20, 2022 6:01 am: > > The hypervisor provides the available VAS GZIP capabilities such > as default or QoS window type and the target available credits in > each type. This patch creates sysfs entries and exports the target, > used and the available credits for each feature. > > This interface can be used by the user space to determine the credits > usage or to set the target credits in the case of QoS type (for DLPAR). > > /sys/devices/vas/vas0/gzip/default_capabilities (default GZIP capabilities) > nr_total_credits /* Total credits available. Can be > /* changed with DLPAR operation */ > nr_used_credits /* Used credits */ > > /sys/devices/vas/vas0/gzip/qos_capabilities (QoS GZIP capabilities) > nr_total_credits > nr_used_credits >
Looks good, thanks Reviewed-by: Nicholas Piggin <npig...@gmail.com> > Signed-off-by: Haren Myneni <ha...@linux.ibm.com> > --- > arch/powerpc/platforms/pseries/Makefile | 2 +- > arch/powerpc/platforms/pseries/vas-sysfs.c | 226 +++++++++++++++++++++ > arch/powerpc/platforms/pseries/vas.c | 6 + > arch/powerpc/platforms/pseries/vas.h | 6 + > 4 files changed, 239 insertions(+), 1 deletion(-) > create mode 100644 arch/powerpc/platforms/pseries/vas-sysfs.c > > diff --git a/arch/powerpc/platforms/pseries/Makefile > b/arch/powerpc/platforms/pseries/Makefile > index ee60b59024b4..29b522d2c755 100644 > --- a/arch/powerpc/platforms/pseries/Makefile > +++ b/arch/powerpc/platforms/pseries/Makefile > @@ -29,6 +29,6 @@ obj-$(CONFIG_PPC_SVM) += svm.o > obj-$(CONFIG_FA_DUMP) += rtas-fadump.o > > obj-$(CONFIG_SUSPEND) += suspend.o > -obj-$(CONFIG_PPC_VAS) += vas.o > +obj-$(CONFIG_PPC_VAS) += vas.o vas-sysfs.o > > obj-$(CONFIG_ARCH_HAS_CC_PLATFORM) += cc_platform.o > diff --git a/arch/powerpc/platforms/pseries/vas-sysfs.c > b/arch/powerpc/platforms/pseries/vas-sysfs.c > new file mode 100644 > index 000000000000..e24d3edb3021 > --- /dev/null > +++ b/arch/powerpc/platforms/pseries/vas-sysfs.c > @@ -0,0 +1,226 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright 2022-23 IBM Corp. > + */ > + > +#define pr_fmt(fmt) "vas: " fmt > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/miscdevice.h> > +#include <linux/kobject.h> > +#include <linux/slab.h> > +#include <linux/mm.h> > + > +#include "vas.h" > + > +#ifdef CONFIG_SYSFS > +static struct kobject *pseries_vas_kobj; > +static struct kobject *gzip_caps_kobj; > + > +struct vas_caps_entry { > + struct kobject kobj; > + struct vas_cop_feat_caps *caps; > +}; > + > +#define to_caps_entry(entry) container_of(entry, struct vas_caps_entry, kobj) > + > +#define sysfs_caps_entry_read(_name) \ > +static ssize_t _name##_show(struct vas_cop_feat_caps *caps, char *buf) > \ > +{ \ > + return sprintf(buf, "%d\n", atomic_read(&caps->_name)); \ > +} > + > +struct vas_sysfs_entry { > + struct attribute attr; > + ssize_t (*show)(struct vas_cop_feat_caps *, char *); > + ssize_t (*store)(struct vas_cop_feat_caps *, const char *, size_t); > +}; > + > +#define VAS_ATTR_RO(_name) \ > + sysfs_caps_entry_read(_name); \ > + static struct vas_sysfs_entry _name##_attribute = __ATTR(_name, \ > + 0444, _name##_show, NULL); > + > +/* > + * Create sysfs interface: > + * /sys/devices/vas/vas0/gzip/default_capabilities > + * This directory contains the following VAS GZIP capabilities > + * for the defaule credit type. > + * /sys/devices/vas/vas0/gzip/default_capabilities/nr_total_credits > + * Total number of default credits assigned to the LPAR which > + * can be changed with DLPAR operation. > + * /sys/devices/vas/vas0/gzip/default_capabilities/nr_used_credits > + * Number of credits used by the user space. One credit will > + * be assigned for each window open. > + * > + * /sys/devices/vas/vas0/gzip/qos_capabilities > + * This directory contains the following VAS GZIP capabilities > + * for the Quality of Service (QoS) credit type. > + * /sys/devices/vas/vas0/gzip/qos_capabilities/nr_total_credits > + * Total number of QoS credits assigned to the LPAR. The user > + * has to define this value using HMC interface. It can be > + * changed dynamically by the user. > + * /sys/devices/vas/vas0/gzip/qos_capabilities/nr_used_credits > + * Number of credits used by the user space. > + */ > + > +VAS_ATTR_RO(nr_total_credits); > +VAS_ATTR_RO(nr_used_credits); > + > +static struct attribute *vas_capab_attrs[] = { > + &nr_total_credits_attribute.attr, > + &nr_used_credits_attribute.attr, > + NULL, > +}; > + > +static ssize_t vas_type_show(struct kobject *kobj, struct attribute *attr, > + char *buf) > +{ > + struct vas_caps_entry *centry; > + struct vas_cop_feat_caps *caps; > + struct vas_sysfs_entry *entry; > + > + centry = to_caps_entry(kobj); > + caps = centry->caps; > + entry = container_of(attr, struct vas_sysfs_entry, attr); > + > + if (!entry->show) > + return -EIO; > + > + return entry->show(caps, buf); > +} > + > +static ssize_t vas_type_store(struct kobject *kobj, struct attribute *attr, > + const char *buf, size_t count) > +{ > + struct vas_caps_entry *centry; > + struct vas_cop_feat_caps *caps; > + struct vas_sysfs_entry *entry; > + > + centry = to_caps_entry(kobj); > + caps = centry->caps; > + entry = container_of(attr, struct vas_sysfs_entry, attr); > + if (!entry->store) > + return -EIO; > + > + return entry->store(caps, buf, count); > +} > + > +static void vas_type_release(struct kobject *kobj) > +{ > + struct vas_caps_entry *centry = to_caps_entry(kobj); > + kfree(centry); > +} > + > +static const struct sysfs_ops vas_sysfs_ops = { > + .show = vas_type_show, > + .store = vas_type_store, > +}; > + > +static struct kobj_type vas_attr_type = { > + .release = vas_type_release, > + .sysfs_ops = &vas_sysfs_ops, > + .default_attrs = vas_capab_attrs, > +}; > + > +static char *vas_caps_kobj_name(struct vas_cop_feat_caps *caps, > + struct kobject **kobj) > +{ > + if (caps->descriptor == VAS_GZIP_QOS_CAPABILITIES) { > + *kobj = gzip_caps_kobj; > + return "qos_capabilities"; > + } else if (caps->descriptor == VAS_GZIP_DEFAULT_CAPABILITIES) { > + *kobj = gzip_caps_kobj; > + return "default_capabilities"; > + } else > + return "Unknown"; > +} > + > +/* > + * Add feature specific capability dir entry. > + * Ex: VDefGzip or VQosGzip > + */ > +int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps) > +{ > + struct vas_caps_entry *centry; > + struct kobject *kobj = NULL; > + int ret = 0; > + char *name; > + > + centry = kzalloc(sizeof(*centry), GFP_KERNEL); > + if (!centry) > + return -ENOMEM; > + > + kobject_init(¢ry->kobj, &vas_attr_type); > + centry->caps = caps; > + name = vas_caps_kobj_name(caps, &kobj); > + > + if (kobj) { > + ret = kobject_add(¢ry->kobj, kobj, "%s", name); > + > + if (ret) { > + pr_err("VAS: sysfs kobject add / event failed %d\n", > + ret); > + kobject_put(¢ry->kobj); > + } > + } > + > + return ret; > +} > + > +static struct miscdevice vas_miscdev = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "vas", > +}; > + > +/* > + * Add VAS and VasCaps (overall capabilities) dir entries. > + */ > +int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps) > +{ > + int ret; > + > + ret = misc_register(&vas_miscdev); > + if (ret < 0) { > + pr_err("%s: register vas misc device failed\n", __func__); > + return ret; > + } > + > + /* > + * The hypervisor does not expose multiple VAS instances, but can > + * see multiple VAS instances on PowerNV. So create 'vas0' directory > + * on pseries. > + */ > + pseries_vas_kobj = kobject_create_and_add("vas0", > + &vas_miscdev.this_device->kobj); > + if (!pseries_vas_kobj) { > + pr_err("Failed to create VAS sysfs entry\n"); > + return -ENOMEM; > + } > + > + if ((vas_caps->feat_type & VAS_GZIP_QOS_FEAT_BIT) || > + (vas_caps->feat_type & VAS_GZIP_DEF_FEAT_BIT)) { > + gzip_caps_kobj = kobject_create_and_add("gzip", > + pseries_vas_kobj); > + if (!gzip_caps_kobj) { > + pr_err("Failed to create VAS GZIP capability entry\n"); > + kobject_put(pseries_vas_kobj); > + return -ENOMEM; > + } > + } > + > + return 0; > +} > + > +#else > +int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps) > +{ > + return 0; > +} > + > +int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps) > +{ > + return 0; > +} > +#endif > diff --git a/arch/powerpc/platforms/pseries/vas.c > b/arch/powerpc/platforms/pseries/vas.c > index 96178dd58adf..ca0ad191229d 100644 > --- a/arch/powerpc/platforms/pseries/vas.c > +++ b/arch/powerpc/platforms/pseries/vas.c > @@ -560,6 +560,10 @@ static int __init get_vas_capabilities(u8 feat, enum > vas_cop_feat_type type, > } > } > > + rc = sysfs_add_vas_caps(caps); > + if (rc) > + return rc; > + > copypaste_feat = true; > > return 0; > @@ -844,6 +848,8 @@ static int __init pseries_vas_init(void) > caps_all.descriptor = be64_to_cpu(hv_caps->descriptor); > caps_all.feat_type = be64_to_cpu(hv_caps->feat_type); > > + sysfs_pseries_vas_init(&caps_all); > + > hv_cop_caps = kmalloc(sizeof(*hv_cop_caps), GFP_KERNEL); > if (!hv_cop_caps) { > rc = -ENOMEM; > diff --git a/arch/powerpc/platforms/pseries/vas.h > b/arch/powerpc/platforms/pseries/vas.h > index 701363cfd7c1..f1bdb776021e 100644 > --- a/arch/powerpc/platforms/pseries/vas.h > +++ b/arch/powerpc/platforms/pseries/vas.h > @@ -30,6 +30,9 @@ > #define VAS_COPY_PASTE_USER_MODE 0x00000001 > #define VAS_COP_OP_USER_MODE 0x00000010 > > +#define VAS_GZIP_QOS_CAPABILITIES 0x56516F73477A6970 > +#define VAS_GZIP_DEFAULT_CAPABILITIES 0x56446566477A6970 > + > /* > * Co-processor feature - GZIP QoS windows or GZIP default windows > */ > @@ -125,4 +128,7 @@ struct pseries_vas_window { > char *name; > int fault_virq; > }; > + > +int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps); > +int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps); > #endif /* _VAS_H */ > -- > 2.27.0 > > >