// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2019 Intel Corporation. All rights rsvd. */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <uapi/linux/idxd.h>
#include "registers.h"
#include "idxd.h"
static char *idxd_wq_type_names[] = {
[IDXD_WQT_NONE] = "none",
[IDXD_WQT_KERNEL] = "kernel",
[IDXD_WQT_USER] = "user",
};
/* IDXD engine attributes */
static ssize_t engine_group_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct idxd_engine *engine = confdev_to_engine(dev);
if (engine->group)
return sysfs_emit(buf, "%d\n", engine->group->id);
else
return sysfs_emit(buf, "%d\n", -1);
}
static ssize_t engine_group_id_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct idxd_engine *engine = confdev_to_engine(dev);
struct idxd_device *idxd = engine->idxd;
long id;
int rc;
struct idxd_group *prevg;
rc = kstrtol(buf, 10, &id);
if (rc < 0)
return -EINVAL;
if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
return -EPERM;
if (id > idxd->max_groups - 1 || id < -1)
return -EINVAL;
if (id == -1) {
if (engine->group) {
engine->group->num_engines--;
engine->group = NULL;
}
return count;
}
prevg = engine->group;
if (prevg)
prevg->num_engines--;
engine->group = idxd->groups[id];
engine->group->num_engines++;
return count;
}
static struct device_attribute dev_attr_engine_group =
__ATTR(group_id, 0644, engine_group_id_show,
engine_group_id_store);
static struct attribute *idxd_engine_attributes[] = {
&dev_attr_engine_group.attr,
NULL,
};
static const struct attribute_group idxd_engine_attribute_group = {
.attrs = idxd_engine_attributes,
};
static const struct attribute_group *idxd_engine_attribute_groups[] = {
&idxd_engine_attribute_group,
NULL,
};
static void idxd_conf_engine_release(struct device *dev)
{
struct idxd_engine *engine = confdev_to_engine(dev);
kfree(engine);
}
struct device_type idxd_engine_device_type = {
.name = "engine",
.release = idxd_conf_engine_release,
.groups = idxd_engine_attribute_groups,
};
/* Group attributes */
static void idxd_set_free_rdbufs(struct idxd_device *idxd)
{
int i, rdbufs;
for (i = 0, rdbufs = 0; i < idxd->max_groups; i++) {
struct idxd_group *g = idxd->groups[i];
rdbufs += g->rdbufs_reserved;
}
idxd->nr_rdbufs = idxd->max_rdbufs - rdbufs;
}
static ssize_t group_read_buffers_reserved_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct idxd_group *group = confdev_to_group(dev);
return sysfs_emit(buf, "%u\n", group->rdbufs_reserved);
}
static ssize_t group_tokens_reserved_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
dev_warn_once(dev, "attribute deprecated, see read_buffers_reserved.\n");
return group_read_buffers_reserved_show(dev, attr, buf);
}
static ssize_t group_read_buffers_reserved_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct idxd_group *group = confdev_to_group(dev);
struct idxd_device *idxd = group->idxd;
unsigned long val;
int rc;
rc = kstrtoul(buf, 10, &val);
if (rc < 0)
return -EINVAL;
if (idxd->data->type == IDXD_TYPE_IAX)
return -EOPNOTSUPP;
if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
return -EPERM;
if (idxd->state == IDXD_DEV_ENABLED)
return -EPERM;
if (val > idxd->max_rdbufs)
return -EINVAL;
if (val > idxd->nr_rdbufs + group->rdbufs_reserved)
return -EINVAL;
group->rdbufs_reserved = val;
idxd_set_free_rdbufs(idxd);
return count;
}
static ssize_t group_tokens_reserved_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
dev_warn_once(dev, "attribute deprecated, see read_buffers_reserved.\n");
return group_read_buffers_reserved_store(dev, attr, buf, count);
}
static struct device_attribute dev_attr_group_tokens_reserved =
__ATTR(tokens_reserved, 0644, group_tokens_reserved_show,
group_tokens_reserved_store);
static struct device_attribute dev_attr_group_read_buffers_reserved =
__ATTR(read_buffers_reserved, 0644, group_read_buffers_reserved_show,
group_read_buffers_reserved_store);
static ssize_t group_read_buffers_allowed_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct idxd_group *group = confdev_to_group(dev);
return sysfs_emit(buf, "%u\n", group->rdbufs_allowed);
}
static ssize_t group_tokens_allowed_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
dev_warn_once(dev, "attribute deprecated, see read_buffers_allowed.\n");
return group_read_buffers_allowed_show(dev, attr, buf);
}
static ssize_t group_read_buffers_allowed_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct idxd_group *group = confdev_to_group(dev);
struct idxd_device *idxd = group->idxd;
unsigned long val;
int rc;
rc = kstrtoul(buf, 10, &val);
if (rc < 0)
return -EINVAL;
if (idxd->data->type == IDXD_TYPE_IAX)
return -EOPNOTSUPP;
if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
return -EPERM;
if (idxd->state == IDXD_DEV_ENABLED)
return -EPERM;
if (val < 4 * group->num_engines ||
val > group->rdbufs_reserved + idxd->nr_rdbufs)
return
|