#include "adf_accel_devices.h"
#include "adf_cfg.h"
#include "adf_common_drv.h"
#include "adf_cfg_device.h"
#include "adf_cfg_sysctl.h"
int
adf_cfg_dev_add(struct adf_accel_dev *accel_dev)
{
struct adf_cfg_device_data *dev_cfg_data;
dev_cfg_data = malloc(sizeof(*dev_cfg_data), M_QAT, M_WAITOK | M_ZERO);
INIT_LIST_HEAD(&dev_cfg_data->sec_list);
sx_init(&dev_cfg_data->lock, "qat cfg data");
accel_dev->cfg = dev_cfg_data;
if (!accel_dev->is_vf) {
if (IS_QAT_GEN4(pci_get_device(GET_DEV(accel_dev)))) {
dev_cfg_data->num_user_processes =
ADF_CFG_STATIC_CONF_USER_PROCESSES_NUM;
strncpy(dev_cfg_data->cfg_mode,
ADF_CFG_KERNEL_USER,
ADF_CFG_MAX_VAL);
if (accel_dev->accel_id % 2 == 0) {
strncpy(dev_cfg_data->cfg_services,
ADF_CFG_SYM_ASYM,
ADF_CFG_MAX_VAL);
} else {
strncpy(dev_cfg_data->cfg_services,
ADF_CFG_DC,
ADF_CFG_MAX_VAL);
}
} else {
strncpy(dev_cfg_data->cfg_mode,
ADF_CFG_KERNEL,
ADF_CFG_MAX_VAL);
dev_cfg_data->num_user_processes = 0;
strncpy(dev_cfg_data->cfg_services,
ADF_CFG_SYM_DC,
ADF_CFG_MAX_VAL);
}
} else {
dev_cfg_data->num_user_processes =
ADF_CFG_STATIC_CONF_USER_PROCESSES_NUM;
strncpy(dev_cfg_data->cfg_mode,
ADF_CFG_KERNEL,
ADF_CFG_MAX_VAL);
strncpy(dev_cfg_data->cfg_services,
"sym;asym",
ADF_CFG_MAX_VAL);
}
if (adf_cfg_sysctl_add(accel_dev)) {
free(dev_cfg_data, M_QAT);
accel_dev->cfg = NULL;
return EFAULT;
}
return 0;
}
static void adf_cfg_section_del_all(struct list_head *head);
void
adf_cfg_del_all(struct adf_accel_dev *accel_dev)
{
struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
sx_xlock(&dev_cfg_data->lock);
adf_cfg_section_del_all(&dev_cfg_data->sec_list);
sx_xunlock(&dev_cfg_data->lock);
clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
}
void
adf_cfg_depot_del_all(struct list_head *head)
{
adf_cfg_section_del_all(head);
}
void
adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
{
struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
if (!dev_cfg_data)
return;
sx_xlock(&dev_cfg_data->lock);
adf_cfg_section_del_all(&dev_cfg_data->sec_list);
sx_xunlock(&dev_cfg_data->lock);
adf_cfg_sysctl_remove(accel_dev);
free(dev_cfg_data, M_QAT);
accel_dev->cfg = NULL;
}
static void
adf_cfg_keyval_add(struct adf_cfg_key_val *new, struct adf_cfg_section *sec)
{
list_add_tail(&new->list, &sec->param_head);
}
static void
adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec)
{
struct list_head *list_ptr, *tmp;
struct list_head *head = &sec->param_head;
list_for_each_prev_safe(list_ptr, tmp, head)
{
struct adf_cfg_key_val *ptr =
list_entry(list_ptr, struct adf_cfg_key_val, list);
if (strncmp(ptr->key, key, sizeof(ptr->key)) != 0)
continue;
list_del(list_ptr);
free(ptr, M_QAT);
break;
}
}
static int
adf_cfg_section_restore_all(struct adf_accel_dev *accel_dev,
struct adf_cfg_depot_list *cfg_depot_list)
{
struct adf_cfg_section *ptr_sec, *iter_sec;
struct adf_cfg_key_val *ptr_key;
struct list_head *list, *tmp;
struct list_head *restore_list = &accel_dev->cfg->sec_list;
struct list_head *head = &cfg_depot_list[accel_dev->accel_id].sec_list;
INIT_LIST_HEAD(restore_list);
list_for_each_prev_safe(list, tmp, head)
{
ptr_sec = list_entry(list, struct adf_cfg_section, list);
iter_sec = malloc(sizeof(*iter_sec), M_QAT, M_WAITOK | M_ZERO);
strlcpy(iter_sec->name, ptr_sec->name, sizeof(iter_sec->name));
INIT_LIST_HEAD(&iter_sec->param_head);
list_for_each_entry(ptr_key, &ptr_sec->param_head, list)
{
struct adf_cfg_key_val *key_val;
key_val =
malloc(sizeof(*key_val), M_QAT, M_WAITOK | M_ZERO);
memcpy(key_val, ptr_key, sizeof(*key_val));
list_add_tail(&key_val->list, &iter_sec->param_head);
}
list_add_tail(&iter_sec->list, restore_list);
}
adf_cfg_section_del_all(head);
return 0;
}
int
adf_cfg_depot_restore_all(struct adf_accel_dev *accel_dev,
struct adf_cfg_depot_list *cfg_depot_list)
{
struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
int ret = 0;
sx_xlock(&dev_cfg_data->lock);
ret = adf_cfg_section_restore_all(accel_dev, cfg_depot_list);
sx_xunlock(&dev_cfg_data->lock);
return ret;
}
static void
adf_cfg_section_del(struct adf_accel_dev *accel_dev, const char *name)
{
struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
if (!sec)
return;
adf_cfg_keyval_del_all(&sec->param_head);
list_del(&sec->list);
free(sec, M_QAT);
}
void
adf_cfg_keyval_del_all(struct list_head *head)
{
struct list_head *list_ptr, *tmp;
list_for_each_prev_safe(list_ptr, tmp, head)
{
struct adf_cfg_key_val *ptr =
list_entry(list_ptr, struct adf_cfg_key_val, list);
list_del(list_ptr);
free(ptr, M_QAT);
}
}
static void
adf_cfg_section_del_all(struct list_head *head)
{
struct adf_cfg_section *ptr;
struct list_head *list, *tmp;
list_for_each_prev_safe(list, tmp, head)
{
ptr = list_entry(list, struct adf_cfg_section, list);
adf_cfg_keyval_del_all(&ptr->param_head);
list_del(list);
free(ptr, M_QAT);
}
}
static struct adf_cfg_key_val *
adf_cfg_key_value_find(struct adf_cfg_section *s, const char *key)
{
struct list_head *list;
list_for_each(list, &s->param_head)
{
struct adf_cfg_key_val *ptr =
list_entry(list, struct adf_cfg_key_val, list);
if (!strncmp(ptr->key, key, sizeof(ptr->key)))
return ptr;
}
return NULL;
}
struct adf_cfg_section *
adf_cfg_sec_find(struct adf_accel_dev *accel_dev, const char *sec_name)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct list_head *list;
list_for_each(list, &cfg->sec_list)
{
struct adf_cfg_section *ptr =
list_entry(list, struct adf_cfg_section, list);
if (!strncmp(ptr->name, sec_name, sizeof(ptr->name)))
return ptr;
}
return NULL;
}
static int
adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
const char *sec_name,
const char *key_name,
char *val)
{
struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
struct adf_cfg_key_val *keyval = NULL;
if (sec)
keyval = adf_cfg_key_value_find(sec, key_name);
if (keyval) {
memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
return 0;
}
return -1;
}
int
adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
const char *section_name,
const char *key,
const void *val,
enum adf_cfg_val_type type)
{
char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct adf_cfg_key_val *key_val;
struct adf_cfg_section *section =
adf_cfg_sec_find(accel_dev, section_name);
if (!section)
return EFAULT;
key_val = malloc(sizeof(*key_val), M_QAT, M_WAITOK | M_ZERO);
INIT_LIST_HEAD(&key_val->list);
strlcpy(key_val->key, key, sizeof(key_val->key));
if (type == ADF_DEC) {
snprintf(key_val->val,
ADF_CFG_MAX_VAL_LEN_IN_BYTES,
"%ld",
(*((const long *)val)));
} else if (type == ADF_STR) {
strlcpy(key_val->val, (const char *)val, sizeof(key_val->val));
} else if (type == ADF_HEX) {
snprintf(key_val->val,
ADF_CFG_MAX_VAL_LEN_IN_BYTES,
"0x%lx",
(unsigned long)val);
} else {
device_printf(GET_DEV(accel_dev), "Unknown type given.\n");
free(key_val, M_QAT);
return -1;
}
key_val->type = type;
if (adf_cfg_key_val_get(accel_dev, section_name, key, temp_val) == 0) {
if (strncmp(temp_val, key_val->val, sizeof(temp_val)) != 0) {
adf_cfg_keyval_remove(key, section);
} else {
free(key_val, M_QAT);
return 0;
}
}
sx_xlock(&cfg->lock);
adf_cfg_keyval_add(key_val, section);
sx_xunlock(&cfg->lock);
return 0;
}
int
adf_cfg_save_section(struct adf_accel_dev *accel_dev,
const char *name,
struct adf_cfg_section *section)
{
struct adf_cfg_key_val *ptr;
struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
if (!sec) {
device_printf(GET_DEV(accel_dev),
"Couldn't find section %s\n",
name);
return EFAULT;
}
strlcpy(section->name, name, sizeof(section->name));
INIT_LIST_HEAD(§ion->param_head);
list_for_each_entry(ptr, &sec->param_head, list)
{
struct adf_cfg_key_val *key_val;
key_val = malloc(sizeof(*key_val), M_QAT, M_WAITOK | M_ZERO);
memcpy(key_val, ptr, sizeof(*key_val));
list_add_tail(&key_val->list, §ion->param_head);
}
return 0;
}
static int
adf_cfg_section_save_all(struct adf_accel_dev *accel_dev,
struct adf_cfg_depot_list *cfg_depot_list)
{
struct adf_cfg_section *ptr_sec, *iter_sec;
struct list_head *list, *tmp, *save_list;
struct list_head *head = &accel_dev->cfg->sec_list;
save_list = &cfg_depot_list[accel_dev->accel_id].sec_list;
list_for_each_prev_safe(list, tmp, head)
{
ptr_sec = list_entry(list, struct adf_cfg_section, list);
iter_sec = malloc(sizeof(*iter_sec), M_QAT, M_WAITOK | M_ZERO);
adf_cfg_save_section(accel_dev, ptr_sec->name, iter_sec);
list_add_tail(&iter_sec->list, save_list);
}
return 0;
}
int
adf_cfg_depot_save_all(struct adf_accel_dev *accel_dev,
struct adf_cfg_depot_list *cfg_depot_list)
{
struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
int ret = 0;
sx_xlock(&dev_cfg_data->lock);
ret = adf_cfg_section_save_all(accel_dev, cfg_depot_list);
sx_xunlock(&dev_cfg_data->lock);
return ret;
}
int
adf_cfg_remove_key_param(struct adf_accel_dev *accel_dev,
const char *section_name,
const char *key)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct adf_cfg_section *section =
adf_cfg_sec_find(accel_dev, section_name);
if (!section)
return EFAULT;
sx_xlock(&cfg->lock);
adf_cfg_keyval_remove(key, section);
sx_xunlock(&cfg->lock);
return 0;
}
int
adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
if (sec)
return 0;
sec = malloc(sizeof(*sec), M_QAT, M_WAITOK | M_ZERO);
strlcpy(sec->name, name, sizeof(sec->name));
INIT_LIST_HEAD(&sec->param_head);
sx_xlock(&cfg->lock);
list_add_tail(&sec->list, &cfg->sec_list);
sx_xunlock(&cfg->lock);
return 0;
}
int
adf_cfg_derived_section_add(struct adf_accel_dev *accel_dev, const char *name)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct adf_cfg_section *sec = NULL;
if (adf_cfg_section_add(accel_dev, name))
return EFAULT;
sec = adf_cfg_sec_find(accel_dev, name);
if (!sec)
return EFAULT;
sx_xlock(&cfg->lock);
sec->is_derived = true;
sx_xunlock(&cfg->lock);
return 0;
}
static int
adf_cfg_restore_key_value_param(struct adf_accel_dev *accel_dev,
const char *section_name,
const char *key,
const char *val,
enum adf_cfg_val_type type)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
struct adf_cfg_key_val *key_val;
struct adf_cfg_section *section =
adf_cfg_sec_find(accel_dev, section_name);
if (!section)
return EFAULT;
key_val = malloc(sizeof(*key_val), M_QAT, M_WAITOK | M_ZERO);
INIT_LIST_HEAD(&key_val->list);
strlcpy(key_val->key, key, sizeof(key_val->key));
strlcpy(key_val->val, val, sizeof(key_val->val));
key_val->type = type;
sx_xlock(&cfg->lock);
adf_cfg_keyval_add(key_val, section);
sx_xunlock(&cfg->lock);
return 0;
}
int
adf_cfg_restore_section(struct adf_accel_dev *accel_dev,
struct adf_cfg_section *section)
{
struct adf_cfg_key_val *ptr;
int ret = 0;
ret = adf_cfg_section_add(accel_dev, section->name);
if (ret)
goto err;
list_for_each_entry(ptr, §ion->param_head, list)
{
ret = adf_cfg_restore_key_value_param(
accel_dev, section->name, ptr->key, ptr->val, ptr->type);
if (ret)
goto err_remove_sec;
}
return 0;
err_remove_sec:
adf_cfg_section_del(accel_dev, section->name);
err:
device_printf(GET_DEV(accel_dev),
"Failed to restore section %s\n",
section->name);
return ret;
}
int
adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,
const char *section,
const char *name,
char *value)
{
struct adf_cfg_device_data *cfg = accel_dev->cfg;
int ret;
sx_slock(&cfg->lock);
ret = adf_cfg_key_val_get(accel_dev, section, name, value);
sx_sunlock(&cfg->lock);
return ret;
}