blob: bedb514d4e30424d23aeb986417b9b838283ef2f [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2023 Intel Corporation */
#define dev_fmt(fmt) "RateLimiting: " fmt
#include <linux/dev_printk.h>
#include <linux/pci.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include "adf_common_drv.h"
#include "adf_rl.h"
#include "adf_sysfs_rl.h"
#define GET_RL_STRUCT(accel_dev) ((accel_dev)->rate_limiting->user_input)
enum rl_ops {
ADD,
UPDATE,
RM,
RM_ALL,
GET,
};
enum rl_params {
RP_MASK,
ID,
CIR,
PIR,
SRV,
CAP_REM_SRV,
};
static const char *const rl_services[] = {
[ADF_SVC_ASYM] = "asym",
[ADF_SVC_SYM] = "sym",
[ADF_SVC_DC] = "dc",
};
static const char *const rl_operations[] = {
[ADD] = "add",
[UPDATE] = "update",
[RM] = "rm",
[RM_ALL] = "rm_all",
[GET] = "get",
};
static int set_param_u(struct device *dev, enum rl_params param, u64 set)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
int ret = 0;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
down_write(&data->lock);
switch (param) {
case RP_MASK:
data->input.rp_mask = set;
break;
case CIR:
data->input.cir = set;
break;
case PIR:
data->input.pir = set;
break;
case SRV:
data->input.srv = set;
break;
case CAP_REM_SRV:
data->cap_rem_srv = set;
break;
default:
ret = -EINVAL;
break;
}
up_write(&data->lock);
return ret;
}
static int set_param_s(struct device *dev, enum rl_params param, int set)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev || param != ID)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
down_write(&data->lock);
data->input.sla_id = set;
up_write(&data->lock);
return 0;
}
static int get_param_u(struct device *dev, enum rl_params param, u64 *get)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
int ret = 0;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
down_read(&data->lock);
switch (param) {
case RP_MASK:
*get = data->input.rp_mask;
break;
case CIR:
*get = data->input.cir;
break;
case PIR:
*get = data->input.pir;
break;
case SRV:
*get = data->input.srv;
break;
default:
ret = -EINVAL;
}
up_read(&data->lock);
return ret;
}
static int get_param_s(struct device *dev, enum rl_params param)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
int ret = 0;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
down_read(&data->lock);
if (param == ID)
ret = data->input.sla_id;
up_read(&data->lock);
return ret;
}
static ssize_t rp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret;
u64 get;
ret = get_param_u(dev, RP_MASK, &get);
if (ret)
return ret;
return sysfs_emit(buf, "%#llx\n", get);
}
static ssize_t rp_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int err;
u64 val;
err = kstrtou64(buf, 16, &val);
if (err)
return err;
err = set_param_u(dev, RP_MASK, val);
if (err)
return err;
return count;
}
static DEVICE_ATTR_RW(rp);
static ssize_t id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%d\n", get_param_s(dev, ID));
}
static ssize_t id_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int err;
int val;
err = kstrtoint(buf, 10, &val);
if (err)
return err;
err = set_param_s(dev, ID, val);
if (err)
return err;
return count;
}
static DEVICE_ATTR_RW(id);
static ssize_t cir_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret;
u64 get;
ret = get_param_u(dev, CIR, &get);
if (ret)
return ret;
return sysfs_emit(buf, "%llu\n", get);
}
static ssize_t cir_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
int err;
err = kstrtouint(buf, 10, &val);
if (err)
return err;
err = set_param_u(dev, CIR, val);
if (err)
return err;
return count;
}
static DEVICE_ATTR_RW(cir);
static ssize_t pir_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret;
u64 get;
ret = get_param_u(dev, PIR, &get);
if (ret)
return ret;
return sysfs_emit(buf, "%llu\n", get);
}
static ssize_t pir_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
int err;
err = kstrtouint(buf, 10, &val);
if (err)
return err;
err = set_param_u(dev, PIR, val);
if (err)
return err;
return count;
}
static DEVICE_ATTR_RW(pir);
static ssize_t srv_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret;
u64 get;
ret = get_param_u(dev, SRV, &get);
if (ret)
return ret;
if (get == ADF_SVC_NONE)
return -EINVAL;
return sysfs_emit(buf, "%s\n", rl_services[get]);
}
static ssize_t srv_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
int ret;
ret = sysfs_match_string(rl_services, buf);
if (ret < 0)
return ret;
val = ret;
ret = set_param_u(dev, SRV, val);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(srv);
static ssize_t cap_rem_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
int ret, rem_cap;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
down_read(&data->lock);
rem_cap = adf_rl_get_capability_remaining(accel_dev, data->cap_rem_srv,
RL_SLA_EMPTY_ID);
up_read(&data->lock);
if (rem_cap < 0)
return rem_cap;
ret = sysfs_emit(buf, "%u\n", rem_cap);
return ret;
}
static ssize_t cap_rem_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
int ret;
ret = sysfs_match_string(rl_services, buf);
if (ret < 0)
return ret;
val = ret;
ret = set_param_u(dev, CAP_REM_SRV, val);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(cap_rem);
static ssize_t sla_op_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct adf_rl_interface_data *data;
struct adf_accel_dev *accel_dev;
int ret;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
data = &GET_RL_STRUCT(accel_dev);
ret = sysfs_match_string(rl_operations, buf);
if (ret < 0)
return ret;
down_write(&data->lock);
switch (ret) {
case ADD:
data->input.parent_id = RL_PARENT_DEFAULT_ID;
data->input.type = RL_LEAF;
data->input.sla_id = 0;
ret = adf_rl_add_sla(accel_dev, &data->input);
if (ret)
goto err_free_lock;
break;
case UPDATE:
ret = adf_rl_update_sla(accel_dev, &data->input);
if (ret)
goto err_free_lock;
break;
case RM:
ret = adf_rl_remove_sla(accel_dev, data->input.sla_id);
if (ret)
goto err_free_lock;
break;
case RM_ALL:
adf_rl_remove_sla_all(accel_dev, false);
break;
case GET:
ret = adf_rl_get_sla(accel_dev, &data->input);
if (ret)
goto err_free_lock;
break;
default:
ret = -EINVAL;
goto err_free_lock;
}
up_write(&data->lock);
return count;
err_free_lock:
up_write(&data->lock);
return ret;
}
static DEVICE_ATTR_WO(sla_op);
static struct attribute *qat_rl_attrs[] = {
&dev_attr_rp.attr,
&dev_attr_id.attr,
&dev_attr_cir.attr,
&dev_attr_pir.attr,
&dev_attr_srv.attr,
&dev_attr_cap_rem.attr,
&dev_attr_sla_op.attr,
NULL,
};
static struct attribute_group qat_rl_group = {
.attrs = qat_rl_attrs,
.name = "qat_rl",
};
int adf_sysfs_rl_add(struct adf_accel_dev *accel_dev)
{
struct adf_rl_interface_data *data;
int ret;
data = &GET_RL_STRUCT(accel_dev);
ret = device_add_group(&GET_DEV(accel_dev), &qat_rl_group);
if (ret)
dev_err(&GET_DEV(accel_dev),
"Failed to create qat_rl attribute group\n");
data->cap_rem_srv = ADF_SVC_NONE;
data->input.srv = ADF_SVC_NONE;
data->sysfs_added = true;
return ret;
}
void adf_sysfs_rl_rm(struct adf_accel_dev *accel_dev)
{
struct adf_rl_interface_data *data;
data = &GET_RL_STRUCT(accel_dev);
if (!data->sysfs_added)
return;
device_remove_group(&GET_DEV(accel_dev), &qat_rl_group);
data->sysfs_added = false;
}