// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2023 Intel Corporation */ #define dev_fmt(fmt) "RateLimiting: " fmt #include #include #include #include #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; }