mirror of https://gitee.com/openkylin/linux.git
360 lines
10 KiB
C
360 lines
10 KiB
C
/*
|
|
This file is provided under a dual BSD/GPLv2 license. When using or
|
|
redistributing this file, you may do so under either license.
|
|
|
|
GPL LICENSE SUMMARY
|
|
Copyright(c) 2014 Intel Corporation.
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of version 2 of the GNU General Public License as
|
|
published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
Contact Information:
|
|
qat-linux@intel.com
|
|
|
|
BSD LICENSE
|
|
Copyright(c) 2014 Intel Corporation.
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the
|
|
distribution.
|
|
* Neither the name of Intel Corporation nor the names of its
|
|
contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <linux/mutex.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/list.h>
|
|
#include <linux/seq_file.h>
|
|
#include "adf_accel_devices.h"
|
|
#include "adf_common_drv.h"
|
|
#include "adf_cfg.h"
|
|
|
|
static DEFINE_MUTEX(qat_cfg_read_lock);
|
|
|
|
static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos)
|
|
{
|
|
struct adf_cfg_device_data *dev_cfg = sfile->private;
|
|
mutex_lock(&qat_cfg_read_lock);
|
|
return seq_list_start(&dev_cfg->sec_list, *pos);
|
|
}
|
|
|
|
static int qat_dev_cfg_show(struct seq_file *sfile, void *v)
|
|
{
|
|
struct list_head *list;
|
|
struct adf_cfg_section *sec =
|
|
list_entry(v, struct adf_cfg_section, list);
|
|
|
|
seq_printf(sfile, "[%s]\n", sec->name);
|
|
list_for_each(list, &sec->param_head) {
|
|
struct adf_cfg_key_val *ptr =
|
|
list_entry(list, struct adf_cfg_key_val, list);
|
|
seq_printf(sfile, "%s = %s\n", ptr->key, ptr->val);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos)
|
|
{
|
|
struct adf_cfg_device_data *dev_cfg = sfile->private;
|
|
return seq_list_next(v, &dev_cfg->sec_list, pos);
|
|
}
|
|
|
|
static void qat_dev_cfg_stop(struct seq_file *sfile, void *v)
|
|
{
|
|
mutex_unlock(&qat_cfg_read_lock);
|
|
}
|
|
|
|
static const struct seq_operations qat_dev_cfg_sops = {
|
|
.start = qat_dev_cfg_start,
|
|
.next = qat_dev_cfg_next,
|
|
.stop = qat_dev_cfg_stop,
|
|
.show = qat_dev_cfg_show
|
|
};
|
|
|
|
static int qat_dev_cfg_open(struct inode *inode, struct file *file)
|
|
{
|
|
int ret = seq_open(file, &qat_dev_cfg_sops);
|
|
|
|
if (!ret) {
|
|
struct seq_file *seq_f = file->private_data;
|
|
seq_f->private = inode->i_private;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations qat_dev_cfg_fops = {
|
|
.open = qat_dev_cfg_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = seq_release
|
|
};
|
|
|
|
/**
|
|
* adf_cfg_dev_add() - Create an acceleration device configuration table.
|
|
* @accel_dev: Pointer to acceleration device.
|
|
*
|
|
* Function creates a configuration table for the given acceleration device.
|
|
* The table stores device specific config values.
|
|
* To be used by QAT device specific drivers.
|
|
*
|
|
* Return: 0 on success, error code othewise.
|
|
*/
|
|
int adf_cfg_dev_add(struct adf_accel_dev *accel_dev)
|
|
{
|
|
struct adf_cfg_device_data *dev_cfg_data;
|
|
|
|
dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL);
|
|
if (!dev_cfg_data)
|
|
return -ENOMEM;
|
|
INIT_LIST_HEAD(&dev_cfg_data->sec_list);
|
|
init_rwsem(&dev_cfg_data->lock);
|
|
accel_dev->cfg = dev_cfg_data;
|
|
|
|
/* accel_dev->debugfs_dir should always be non-NULL here */
|
|
dev_cfg_data->debug = debugfs_create_file("dev_cfg", S_IRUSR,
|
|
accel_dev->debugfs_dir,
|
|
dev_cfg_data,
|
|
&qat_dev_cfg_fops);
|
|
if (!dev_cfg_data->debug) {
|
|
pr_err("QAT: Failed to create qat cfg debugfs entry.\n");
|
|
kfree(dev_cfg_data);
|
|
accel_dev->cfg = NULL;
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adf_cfg_dev_add);
|
|
|
|
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;
|
|
|
|
down_write(&dev_cfg_data->lock);
|
|
adf_cfg_section_del_all(&dev_cfg_data->sec_list);
|
|
up_write(&dev_cfg_data->lock);
|
|
}
|
|
|
|
/**
|
|
* adf_cfg_dev_remove() - Clears acceleration device configuration table.
|
|
* @accel_dev: Pointer to acceleration device.
|
|
*
|
|
* Function removes configuration table from the given acceleration device
|
|
* and frees all allocated memory.
|
|
* To be used by QAT device specific drivers.
|
|
*
|
|
* Return: void
|
|
*/
|
|
void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
|
|
{
|
|
struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
|
|
|
|
down_write(&dev_cfg_data->lock);
|
|
adf_cfg_section_del_all(&dev_cfg_data->sec_list);
|
|
up_write(&dev_cfg_data->lock);
|
|
debugfs_remove(dev_cfg_data->debug);
|
|
kfree(dev_cfg_data);
|
|
accel_dev->cfg = NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adf_cfg_dev_remove);
|
|
|
|
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_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);
|
|
kfree(ptr);
|
|
}
|
|
}
|
|
|
|
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);
|
|
kfree(ptr);
|
|
}
|
|
}
|
|
|
|
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 (!strcmp(ptr->key, key))
|
|
return ptr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static 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 (!strcmp(ptr->name, sec_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;
|
|
}
|
|
|
|
/**
|
|
* adf_cfg_add_key_value_param() - Add key-value config entry to config table.
|
|
* @accel_dev: Pointer to acceleration device.
|
|
* @section_name: Name of the section where the param will be added
|
|
* @key: The key string
|
|
* @val: Value pain for the given @key
|
|
* @type: Type - string, int or address
|
|
*
|
|
* Function adds configuration key - value entry in the appropriate section
|
|
* in the given acceleration device
|
|
* To be used by QAT device specific drivers.
|
|
*
|
|
* Return: 0 on success, error code othewise.
|
|
*/
|
|
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)
|
|
{
|
|
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 = kzalloc(sizeof(*key_val), GFP_KERNEL);
|
|
if (!key_val)
|
|
return -ENOMEM;
|
|
|
|
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", (*((long *)val)));
|
|
} else if (type == ADF_STR) {
|
|
strlcpy(key_val->val, (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 {
|
|
pr_err("QAT: Unknown type given.\n");
|
|
kfree(key_val);
|
|
return -1;
|
|
}
|
|
key_val->type = type;
|
|
down_write(&cfg->lock);
|
|
adf_cfg_keyval_add(key_val, section);
|
|
up_write(&cfg->lock);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);
|
|
|
|
/**
|
|
* adf_cfg_section_add() - Add config section entry to config table.
|
|
* @accel_dev: Pointer to acceleration device.
|
|
* @name: Name of the section
|
|
*
|
|
* Function adds configuration section where key - value entries
|
|
* will be stored.
|
|
* To be used by QAT device specific drivers.
|
|
*
|
|
* Return: 0 on success, error code othewise.
|
|
*/
|
|
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 = kzalloc(sizeof(*sec), GFP_KERNEL);
|
|
if (!sec)
|
|
return -ENOMEM;
|
|
|
|
strlcpy(sec->name, name, sizeof(sec->name));
|
|
INIT_LIST_HEAD(&sec->param_head);
|
|
down_write(&cfg->lock);
|
|
list_add_tail(&sec->list, &cfg->sec_list);
|
|
up_write(&cfg->lock);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adf_cfg_section_add);
|
|
|
|
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;
|
|
|
|
down_read(&cfg->lock);
|
|
ret = adf_cfg_key_val_get(accel_dev, section, name, value);
|
|
up_read(&cfg->lock);
|
|
return ret;
|
|
}
|