Path: blob/master/drivers/crypto/intel/qat/qat_common/adf_cfg.c
29278 views
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)1/* Copyright(c) 2014 - 2020 Intel Corporation */2#include <linux/mutex.h>3#include <linux/slab.h>4#include <linux/list.h>5#include <linux/seq_file.h>6#include "adf_accel_devices.h"7#include "adf_cfg.h"8#include "adf_common_drv.h"910static DEFINE_MUTEX(qat_cfg_read_lock);1112static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos)13{14struct adf_cfg_device_data *dev_cfg = sfile->private;1516mutex_lock(&qat_cfg_read_lock);17return seq_list_start(&dev_cfg->sec_list, *pos);18}1920static int qat_dev_cfg_show(struct seq_file *sfile, void *v)21{22struct list_head *list;23struct adf_cfg_section *sec =24list_entry(v, struct adf_cfg_section, list);2526seq_printf(sfile, "[%s]\n", sec->name);27list_for_each(list, &sec->param_head) {28struct adf_cfg_key_val *ptr =29list_entry(list, struct adf_cfg_key_val, list);30seq_printf(sfile, "%s = %s\n", ptr->key, ptr->val);31}32return 0;33}3435static void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos)36{37struct adf_cfg_device_data *dev_cfg = sfile->private;3839return seq_list_next(v, &dev_cfg->sec_list, pos);40}4142static void qat_dev_cfg_stop(struct seq_file *sfile, void *v)43{44mutex_unlock(&qat_cfg_read_lock);45}4647static const struct seq_operations qat_dev_cfg_sops = {48.start = qat_dev_cfg_start,49.next = qat_dev_cfg_next,50.stop = qat_dev_cfg_stop,51.show = qat_dev_cfg_show52};5354DEFINE_SEQ_ATTRIBUTE(qat_dev_cfg);5556/**57* adf_cfg_dev_add() - Create an acceleration device configuration table.58* @accel_dev: Pointer to acceleration device.59*60* Function creates a configuration table for the given acceleration device.61* The table stores device specific config values.62* To be used by QAT device specific drivers.63*64* Return: 0 on success, error code otherwise.65*/66int adf_cfg_dev_add(struct adf_accel_dev *accel_dev)67{68struct adf_cfg_device_data *dev_cfg_data;6970dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL);71if (!dev_cfg_data)72return -ENOMEM;73INIT_LIST_HEAD(&dev_cfg_data->sec_list);74init_rwsem(&dev_cfg_data->lock);75accel_dev->cfg = dev_cfg_data;76return 0;77}78EXPORT_SYMBOL_GPL(adf_cfg_dev_add);7980void adf_cfg_dev_dbgfs_add(struct adf_accel_dev *accel_dev)81{82struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;8384dev_cfg_data->debug = debugfs_create_file("dev_cfg", 0400,85accel_dev->debugfs_dir,86dev_cfg_data,87&qat_dev_cfg_fops);88}8990void adf_cfg_dev_dbgfs_rm(struct adf_accel_dev *accel_dev)91{92struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;9394if (!dev_cfg_data)95return;9697debugfs_remove(dev_cfg_data->debug);98dev_cfg_data->debug = NULL;99}100101static void adf_cfg_section_del_all(struct list_head *head);102static void adf_cfg_section_del_all_except(struct list_head *head,103const char *section_name);104105void adf_cfg_del_all(struct adf_accel_dev *accel_dev)106{107struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;108109down_write(&dev_cfg_data->lock);110adf_cfg_section_del_all(&dev_cfg_data->sec_list);111up_write(&dev_cfg_data->lock);112clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);113}114115void adf_cfg_del_all_except(struct adf_accel_dev *accel_dev,116const char *section_name)117{118struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;119120down_write(&dev_cfg_data->lock);121adf_cfg_section_del_all_except(&dev_cfg_data->sec_list, section_name);122up_write(&dev_cfg_data->lock);123clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);124}125126/**127* adf_cfg_dev_remove() - Clears acceleration device configuration table.128* @accel_dev: Pointer to acceleration device.129*130* Function removes configuration table from the given acceleration device131* and frees all allocated memory.132* To be used by QAT device specific drivers.133*134* Return: void135*/136void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)137{138struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;139140if (!dev_cfg_data)141return;142143down_write(&dev_cfg_data->lock);144adf_cfg_section_del_all(&dev_cfg_data->sec_list);145up_write(&dev_cfg_data->lock);146kfree(dev_cfg_data);147accel_dev->cfg = NULL;148}149EXPORT_SYMBOL_GPL(adf_cfg_dev_remove);150151static void adf_cfg_keyval_add(struct adf_cfg_key_val *new,152struct adf_cfg_section *sec)153{154list_add_tail(&new->list, &sec->param_head);155}156157static void adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec)158{159struct list_head *head = &sec->param_head;160struct list_head *list_ptr, *tmp;161162list_for_each_prev_safe(list_ptr, tmp, head) {163struct adf_cfg_key_val *ptr =164list_entry(list_ptr, struct adf_cfg_key_val, list);165166if (strncmp(ptr->key, key, sizeof(ptr->key)))167continue;168169list_del(list_ptr);170kfree(ptr);171break;172}173}174175static void adf_cfg_keyval_del_all(struct list_head *head)176{177struct list_head *list_ptr, *tmp;178179list_for_each_prev_safe(list_ptr, tmp, head) {180struct adf_cfg_key_val *ptr =181list_entry(list_ptr, struct adf_cfg_key_val, list);182list_del(list_ptr);183kfree(ptr);184}185}186187static void adf_cfg_section_del_all(struct list_head *head)188{189struct adf_cfg_section *ptr;190struct list_head *list, *tmp;191192list_for_each_prev_safe(list, tmp, head) {193ptr = list_entry(list, struct adf_cfg_section, list);194adf_cfg_keyval_del_all(&ptr->param_head);195list_del(list);196kfree(ptr);197}198}199200static void adf_cfg_section_del_all_except(struct list_head *head,201const char *section_name)202{203struct list_head *list, *tmp;204struct adf_cfg_section *ptr;205206list_for_each_prev_safe(list, tmp, head) {207ptr = list_entry(list, struct adf_cfg_section, list);208if (!strcmp(ptr->name, section_name))209continue;210adf_cfg_keyval_del_all(&ptr->param_head);211list_del(list);212kfree(ptr);213}214}215216static struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s,217const char *key)218{219struct list_head *list;220221list_for_each(list, &s->param_head) {222struct adf_cfg_key_val *ptr =223list_entry(list, struct adf_cfg_key_val, list);224if (!strcmp(ptr->key, key))225return ptr;226}227return NULL;228}229230static struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev,231const char *sec_name)232{233struct adf_cfg_device_data *cfg = accel_dev->cfg;234struct list_head *list;235236list_for_each(list, &cfg->sec_list) {237struct adf_cfg_section *ptr =238list_entry(list, struct adf_cfg_section, list);239if (!strcmp(ptr->name, sec_name))240return ptr;241}242return NULL;243}244245static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,246const char *sec_name,247const char *key_name,248char *val)249{250struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);251struct adf_cfg_key_val *keyval = NULL;252253if (sec)254keyval = adf_cfg_key_value_find(sec, key_name);255if (keyval) {256memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);257return 0;258}259return -ENODATA;260}261262/**263* adf_cfg_add_key_value_param() - Add key-value config entry to config table.264* @accel_dev: Pointer to acceleration device.265* @section_name: Name of the section where the param will be added266* @key: The key string267* @val: Value pain for the given @key268* @type: Type - string, int or address269*270* Function adds configuration key - value entry in the appropriate section271* in the given acceleration device. If the key exists already, the value272* is updated.273* To be used by QAT device specific drivers.274*275* Return: 0 on success, error code otherwise.276*/277int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,278const char *section_name,279const char *key, const void *val,280enum adf_cfg_val_type type)281{282struct adf_cfg_device_data *cfg = accel_dev->cfg;283struct adf_cfg_key_val *key_val;284struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,285section_name);286char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];287288if (!section)289return -EFAULT;290291key_val = kzalloc(sizeof(*key_val), GFP_KERNEL);292if (!key_val)293return -ENOMEM;294295INIT_LIST_HEAD(&key_val->list);296strscpy(key_val->key, key, sizeof(key_val->key));297298if (type == ADF_DEC) {299snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,300"%ld", (*((long *)val)));301} else if (type == ADF_STR) {302strscpy(key_val->val, (char *)val, sizeof(key_val->val));303} else if (type == ADF_HEX) {304snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,305"0x%lx", (unsigned long)val);306} else {307dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");308kfree(key_val);309return -EINVAL;310}311key_val->type = type;312313/* Add the key-value pair as below policy:314* 1. if the key doesn't exist, add it;315* 2. if the key already exists with a different value then update it316* to the new value (the key is deleted and the newly created317* key_val containing the new value is added to the database);318* 3. if the key exists with the same value, then return without doing319* anything (the newly created key_val is freed).320*/321down_write(&cfg->lock);322if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) {323if (strncmp(temp_val, key_val->val, sizeof(temp_val))) {324adf_cfg_keyval_remove(key, section);325} else {326kfree(key_val);327goto out;328}329}330331adf_cfg_keyval_add(key_val, section);332333out:334up_write(&cfg->lock);335return 0;336}337EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);338339/**340* adf_cfg_section_add() - Add config section entry to config table.341* @accel_dev: Pointer to acceleration device.342* @name: Name of the section343*344* Function adds configuration section where key - value entries345* will be stored.346* To be used by QAT device specific drivers.347*348* Return: 0 on success, error code otherwise.349*/350int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)351{352struct adf_cfg_device_data *cfg = accel_dev->cfg;353struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);354355if (sec)356return 0;357358sec = kzalloc(sizeof(*sec), GFP_KERNEL);359if (!sec)360return -ENOMEM;361362strscpy(sec->name, name, sizeof(sec->name));363INIT_LIST_HEAD(&sec->param_head);364down_write(&cfg->lock);365list_add_tail(&sec->list, &cfg->sec_list);366up_write(&cfg->lock);367return 0;368}369EXPORT_SYMBOL_GPL(adf_cfg_section_add);370371int adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,372const char *section, const char *name,373char *value)374{375struct adf_cfg_device_data *cfg = accel_dev->cfg;376int ret;377378down_read(&cfg->lock);379ret = adf_cfg_key_val_get(accel_dev, section, name, value);380up_read(&cfg->lock);381return ret;382}383EXPORT_SYMBOL_GPL(adf_cfg_get_param_value);384385386