Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2022-23 IBM Corp.
0004  */
0005 
0006 #define pr_fmt(fmt) "vas: " fmt
0007 
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/miscdevice.h>
0011 #include <linux/kobject.h>
0012 #include <linux/slab.h>
0013 #include <linux/mm.h>
0014 
0015 #include "vas.h"
0016 
0017 #ifdef CONFIG_SYSFS
0018 static struct kobject *pseries_vas_kobj;
0019 static struct kobject *gzip_caps_kobj;
0020 
0021 struct vas_caps_entry {
0022     struct kobject kobj;
0023     struct vas_cop_feat_caps *caps;
0024 };
0025 
0026 #define to_caps_entry(entry) container_of(entry, struct vas_caps_entry, kobj)
0027 
0028 /*
0029  * This function is used to get the notification from the drmgr when
0030  * QoS credits are changed.
0031  */
0032 static ssize_t update_total_credits_store(struct vas_cop_feat_caps *caps,
0033                         const char *buf, size_t count)
0034 {
0035     int err;
0036     u16 creds;
0037 
0038     err = kstrtou16(buf, 0, &creds);
0039     /*
0040      * The user space interface from the management console
0041      * notifies OS with the new QoS credits and then the
0042      * hypervisor. So OS has to use this new credits value
0043      * and reconfigure VAS windows (close or reopen depends
0044      * on the credits available) instead of depending on VAS
0045      * QoS capabilities from the hypervisor.
0046      */
0047     if (!err)
0048         err = vas_reconfig_capabilties(caps->win_type, creds);
0049 
0050     if (err)
0051         return -EINVAL;
0052 
0053     pr_info("Set QoS total credits %u\n", creds);
0054 
0055     return count;
0056 }
0057 
0058 #define sysfs_caps_entry_read(_name)                    \
0059 static ssize_t _name##_show(struct vas_cop_feat_caps *caps, char *buf)  \
0060 {                                   \
0061     return sprintf(buf, "%d\n", atomic_read(&caps->_name)); \
0062 }
0063 
0064 struct vas_sysfs_entry {
0065     struct attribute attr;
0066     ssize_t (*show)(struct vas_cop_feat_caps *, char *);
0067     ssize_t (*store)(struct vas_cop_feat_caps *, const char *, size_t);
0068 };
0069 
0070 #define VAS_ATTR_RO(_name)  \
0071     sysfs_caps_entry_read(_name);       \
0072     static struct vas_sysfs_entry _name##_attribute = __ATTR(_name, \
0073                 0444, _name##_show, NULL);
0074 
0075 /*
0076  * Create sysfs interface:
0077  * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities
0078  *  This directory contains the following VAS GZIP capabilities
0079  *  for the default credit type.
0080  * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities/nr_total_credits
0081  *  Total number of default credits assigned to the LPAR which
0082  *  can be changed with DLPAR operation.
0083  * /sys/devices/virtual/misc/vas/vas0/gzip/default_capabilities/nr_used_credits
0084  *  Number of credits used by the user space. One credit will
0085  *  be assigned for each window open.
0086  *
0087  * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities
0088  *  This directory contains the following VAS GZIP capabilities
0089  *  for the Quality of Service (QoS) credit type.
0090  * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/nr_total_credits
0091  *  Total number of QoS credits assigned to the LPAR. The user
0092  *  has to define this value using HMC interface. It can be
0093  *  changed dynamically by the user.
0094  * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/nr_used_credits
0095  *  Number of credits used by the user space.
0096  * /sys/devices/virtual/misc/vas/vas0/gzip/qos_capabilities/update_total_credits
0097  *  Update total QoS credits dynamically
0098  */
0099 
0100 VAS_ATTR_RO(nr_total_credits);
0101 VAS_ATTR_RO(nr_used_credits);
0102 
0103 static struct vas_sysfs_entry update_total_credits_attribute =
0104     __ATTR(update_total_credits, 0200, NULL, update_total_credits_store);
0105 
0106 static struct attribute *vas_def_capab_attrs[] = {
0107     &nr_total_credits_attribute.attr,
0108     &nr_used_credits_attribute.attr,
0109     NULL,
0110 };
0111 ATTRIBUTE_GROUPS(vas_def_capab);
0112 
0113 static struct attribute *vas_qos_capab_attrs[] = {
0114     &nr_total_credits_attribute.attr,
0115     &nr_used_credits_attribute.attr,
0116     &update_total_credits_attribute.attr,
0117     NULL,
0118 };
0119 ATTRIBUTE_GROUPS(vas_qos_capab);
0120 
0121 static ssize_t vas_type_show(struct kobject *kobj, struct attribute *attr,
0122                  char *buf)
0123 {
0124     struct vas_caps_entry *centry;
0125     struct vas_cop_feat_caps *caps;
0126     struct vas_sysfs_entry *entry;
0127 
0128     centry = to_caps_entry(kobj);
0129     caps = centry->caps;
0130     entry = container_of(attr, struct vas_sysfs_entry, attr);
0131 
0132     if (!entry->show)
0133         return -EIO;
0134 
0135     return entry->show(caps, buf);
0136 }
0137 
0138 static ssize_t vas_type_store(struct kobject *kobj, struct attribute *attr,
0139                   const char *buf, size_t count)
0140 {
0141     struct vas_caps_entry *centry;
0142     struct vas_cop_feat_caps *caps;
0143     struct vas_sysfs_entry *entry;
0144 
0145     centry = to_caps_entry(kobj);
0146     caps = centry->caps;
0147     entry = container_of(attr, struct vas_sysfs_entry, attr);
0148     if (!entry->store)
0149         return -EIO;
0150 
0151     return entry->store(caps, buf, count);
0152 }
0153 
0154 static void vas_type_release(struct kobject *kobj)
0155 {
0156     struct vas_caps_entry *centry = to_caps_entry(kobj);
0157     kfree(centry);
0158 }
0159 
0160 static const struct sysfs_ops vas_sysfs_ops = {
0161     .show   =   vas_type_show,
0162     .store  =   vas_type_store,
0163 };
0164 
0165 static struct kobj_type vas_def_attr_type = {
0166         .release    =   vas_type_release,
0167         .sysfs_ops      =       &vas_sysfs_ops,
0168         .default_groups =   vas_def_capab_groups,
0169 };
0170 
0171 static struct kobj_type vas_qos_attr_type = {
0172         .release    =   vas_type_release,
0173         .sysfs_ops  =   &vas_sysfs_ops,
0174         .default_groups =   vas_qos_capab_groups,
0175 };
0176 
0177 static char *vas_caps_kobj_name(struct vas_caps_entry *centry,
0178                 struct kobject **kobj)
0179 {
0180     struct vas_cop_feat_caps *caps = centry->caps;
0181 
0182     if (caps->descriptor == VAS_GZIP_QOS_CAPABILITIES) {
0183         kobject_init(&centry->kobj, &vas_qos_attr_type);
0184         *kobj = gzip_caps_kobj;
0185         return "qos_capabilities";
0186     } else if (caps->descriptor == VAS_GZIP_DEFAULT_CAPABILITIES) {
0187         kobject_init(&centry->kobj, &vas_def_attr_type);
0188         *kobj = gzip_caps_kobj;
0189         return "default_capabilities";
0190     } else
0191         return "Unknown";
0192 }
0193 
0194 /*
0195  * Add feature specific capability dir entry.
0196  * Ex: VDefGzip or VQosGzip
0197  */
0198 int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps)
0199 {
0200     struct vas_caps_entry *centry;
0201     struct kobject *kobj = NULL;
0202     int ret = 0;
0203     char *name;
0204 
0205     centry = kzalloc(sizeof(*centry), GFP_KERNEL);
0206     if (!centry)
0207         return -ENOMEM;
0208 
0209     centry->caps = caps;
0210     name  = vas_caps_kobj_name(centry, &kobj);
0211 
0212     if (kobj) {
0213         ret = kobject_add(&centry->kobj, kobj, "%s", name);
0214 
0215         if (ret) {
0216             pr_err("VAS: sysfs kobject add / event failed %d\n",
0217                     ret);
0218             kobject_put(&centry->kobj);
0219         }
0220     }
0221 
0222     return ret;
0223 }
0224 
0225 static struct miscdevice vas_miscdev = {
0226     .minor = MISC_DYNAMIC_MINOR,
0227     .name = "vas",
0228 };
0229 
0230 /*
0231  * Add VAS and VasCaps (overall capabilities) dir entries.
0232  */
0233 int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps)
0234 {
0235     int ret;
0236 
0237     ret = misc_register(&vas_miscdev);
0238     if (ret < 0) {
0239         pr_err("%s: register vas misc device failed\n", __func__);
0240         return ret;
0241     }
0242 
0243     /*
0244      * The hypervisor does not expose multiple VAS instances, but can
0245      * see multiple VAS instances on PowerNV. So create 'vas0' directory
0246      * on pseries.
0247      */
0248     pseries_vas_kobj = kobject_create_and_add("vas0",
0249                     &vas_miscdev.this_device->kobj);
0250     if (!pseries_vas_kobj) {
0251         misc_deregister(&vas_miscdev);
0252         pr_err("Failed to create VAS sysfs entry\n");
0253         return -ENOMEM;
0254     }
0255 
0256     if ((vas_caps->feat_type & VAS_GZIP_QOS_FEAT_BIT) ||
0257         (vas_caps->feat_type & VAS_GZIP_DEF_FEAT_BIT)) {
0258         gzip_caps_kobj = kobject_create_and_add("gzip",
0259                                pseries_vas_kobj);
0260         if (!gzip_caps_kobj) {
0261             pr_err("Failed to create VAS GZIP capability entry\n");
0262             kobject_put(pseries_vas_kobj);
0263             misc_deregister(&vas_miscdev);
0264             return -ENOMEM;
0265         }
0266     }
0267 
0268     return 0;
0269 }
0270 
0271 #else
0272 int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps)
0273 {
0274     return 0;
0275 }
0276 
0277 int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps)
0278 {
0279     return 0;
0280 }
0281 #endif