18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
28c2ecf20Sopenharmony_ci/* Copyright(c) 2014 - 2020 Intel Corporation */
38c2ecf20Sopenharmony_ci#include <linux/mutex.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include <linux/list.h>
68c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
78c2ecf20Sopenharmony_ci#include "adf_accel_devices.h"
88c2ecf20Sopenharmony_ci#include "adf_cfg.h"
98c2ecf20Sopenharmony_ci#include "adf_common_drv.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(qat_cfg_read_lock);
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *dev_cfg = sfile->private;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	mutex_lock(&qat_cfg_read_lock);
188c2ecf20Sopenharmony_ci	return seq_list_start(&dev_cfg->sec_list, *pos);
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic int qat_dev_cfg_show(struct seq_file *sfile, void *v)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct list_head *list;
248c2ecf20Sopenharmony_ci	struct adf_cfg_section *sec =
258c2ecf20Sopenharmony_ci				list_entry(v, struct adf_cfg_section, list);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	seq_printf(sfile, "[%s]\n", sec->name);
288c2ecf20Sopenharmony_ci	list_for_each(list, &sec->param_head) {
298c2ecf20Sopenharmony_ci		struct adf_cfg_key_val *ptr =
308c2ecf20Sopenharmony_ci			list_entry(list, struct adf_cfg_key_val, list);
318c2ecf20Sopenharmony_ci		seq_printf(sfile, "%s = %s\n", ptr->key, ptr->val);
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci	return 0;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *dev_cfg = sfile->private;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return seq_list_next(v, &dev_cfg->sec_list, pos);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void qat_dev_cfg_stop(struct seq_file *sfile, void *v)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	mutex_unlock(&qat_cfg_read_lock);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic const struct seq_operations qat_dev_cfg_sops = {
498c2ecf20Sopenharmony_ci	.start = qat_dev_cfg_start,
508c2ecf20Sopenharmony_ci	.next = qat_dev_cfg_next,
518c2ecf20Sopenharmony_ci	.stop = qat_dev_cfg_stop,
528c2ecf20Sopenharmony_ci	.show = qat_dev_cfg_show
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(qat_dev_cfg);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/**
588c2ecf20Sopenharmony_ci * adf_cfg_dev_add() - Create an acceleration device configuration table.
598c2ecf20Sopenharmony_ci * @accel_dev:  Pointer to acceleration device.
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Function creates a configuration table for the given acceleration device.
628c2ecf20Sopenharmony_ci * The table stores device specific config values.
638c2ecf20Sopenharmony_ci * To be used by QAT device specific drivers.
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Return: 0 on success, error code otherwise.
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_ciint adf_cfg_dev_add(struct adf_accel_dev *accel_dev)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *dev_cfg_data;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL);
728c2ecf20Sopenharmony_ci	if (!dev_cfg_data)
738c2ecf20Sopenharmony_ci		return -ENOMEM;
748c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dev_cfg_data->sec_list);
758c2ecf20Sopenharmony_ci	init_rwsem(&dev_cfg_data->lock);
768c2ecf20Sopenharmony_ci	accel_dev->cfg = dev_cfg_data;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* accel_dev->debugfs_dir should always be non-NULL here */
798c2ecf20Sopenharmony_ci	dev_cfg_data->debug = debugfs_create_file("dev_cfg", S_IRUSR,
808c2ecf20Sopenharmony_ci						  accel_dev->debugfs_dir,
818c2ecf20Sopenharmony_ci						  dev_cfg_data,
828c2ecf20Sopenharmony_ci						  &qat_dev_cfg_fops);
838c2ecf20Sopenharmony_ci	return 0;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adf_cfg_dev_add);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void adf_cfg_section_del_all(struct list_head *head);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_civoid adf_cfg_del_all(struct adf_accel_dev *accel_dev)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	down_write(&dev_cfg_data->lock);
948c2ecf20Sopenharmony_ci	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
958c2ecf20Sopenharmony_ci	up_write(&dev_cfg_data->lock);
968c2ecf20Sopenharmony_ci	clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/**
1008c2ecf20Sopenharmony_ci * adf_cfg_dev_remove() - Clears acceleration device configuration table.
1018c2ecf20Sopenharmony_ci * @accel_dev:  Pointer to acceleration device.
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci * Function removes configuration table from the given acceleration device
1048c2ecf20Sopenharmony_ci * and frees all allocated memory.
1058c2ecf20Sopenharmony_ci * To be used by QAT device specific drivers.
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * Return: void
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_civoid adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!dev_cfg_data)
1148c2ecf20Sopenharmony_ci		return;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	down_write(&dev_cfg_data->lock);
1178c2ecf20Sopenharmony_ci	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
1188c2ecf20Sopenharmony_ci	up_write(&dev_cfg_data->lock);
1198c2ecf20Sopenharmony_ci	debugfs_remove(dev_cfg_data->debug);
1208c2ecf20Sopenharmony_ci	kfree(dev_cfg_data);
1218c2ecf20Sopenharmony_ci	accel_dev->cfg = NULL;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adf_cfg_dev_remove);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void adf_cfg_keyval_add(struct adf_cfg_key_val *new,
1268c2ecf20Sopenharmony_ci			       struct adf_cfg_section *sec)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	list_add_tail(&new->list, &sec->param_head);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void adf_cfg_keyval_del_all(struct list_head *head)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct list_head *list_ptr, *tmp;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	list_for_each_prev_safe(list_ptr, tmp, head) {
1368c2ecf20Sopenharmony_ci		struct adf_cfg_key_val *ptr =
1378c2ecf20Sopenharmony_ci			list_entry(list_ptr, struct adf_cfg_key_val, list);
1388c2ecf20Sopenharmony_ci		list_del(list_ptr);
1398c2ecf20Sopenharmony_ci		kfree(ptr);
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void adf_cfg_section_del_all(struct list_head *head)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct adf_cfg_section *ptr;
1468c2ecf20Sopenharmony_ci	struct list_head *list, *tmp;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	list_for_each_prev_safe(list, tmp, head) {
1498c2ecf20Sopenharmony_ci		ptr = list_entry(list, struct adf_cfg_section, list);
1508c2ecf20Sopenharmony_ci		adf_cfg_keyval_del_all(&ptr->param_head);
1518c2ecf20Sopenharmony_ci		list_del(list);
1528c2ecf20Sopenharmony_ci		kfree(ptr);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s,
1578c2ecf20Sopenharmony_ci						      const char *key)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct list_head *list;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	list_for_each(list, &s->param_head) {
1628c2ecf20Sopenharmony_ci		struct adf_cfg_key_val *ptr =
1638c2ecf20Sopenharmony_ci			list_entry(list, struct adf_cfg_key_val, list);
1648c2ecf20Sopenharmony_ci		if (!strcmp(ptr->key, key))
1658c2ecf20Sopenharmony_ci			return ptr;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci	return NULL;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev,
1718c2ecf20Sopenharmony_ci						const char *sec_name)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *cfg = accel_dev->cfg;
1748c2ecf20Sopenharmony_ci	struct list_head *list;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	list_for_each(list, &cfg->sec_list) {
1778c2ecf20Sopenharmony_ci		struct adf_cfg_section *ptr =
1788c2ecf20Sopenharmony_ci			list_entry(list, struct adf_cfg_section, list);
1798c2ecf20Sopenharmony_ci		if (!strcmp(ptr->name, sec_name))
1808c2ecf20Sopenharmony_ci			return ptr;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	return NULL;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
1868c2ecf20Sopenharmony_ci			       const char *sec_name,
1878c2ecf20Sopenharmony_ci			       const char *key_name,
1888c2ecf20Sopenharmony_ci			       char *val)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
1918c2ecf20Sopenharmony_ci	struct adf_cfg_key_val *keyval = NULL;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (sec)
1948c2ecf20Sopenharmony_ci		keyval = adf_cfg_key_value_find(sec, key_name);
1958c2ecf20Sopenharmony_ci	if (keyval) {
1968c2ecf20Sopenharmony_ci		memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
1978c2ecf20Sopenharmony_ci		return 0;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	return -1;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/**
2038c2ecf20Sopenharmony_ci * adf_cfg_add_key_value_param() - Add key-value config entry to config table.
2048c2ecf20Sopenharmony_ci * @accel_dev:  Pointer to acceleration device.
2058c2ecf20Sopenharmony_ci * @section_name: Name of the section where the param will be added
2068c2ecf20Sopenharmony_ci * @key: The key string
2078c2ecf20Sopenharmony_ci * @val: Value pain for the given @key
2088c2ecf20Sopenharmony_ci * @type: Type - string, int or address
2098c2ecf20Sopenharmony_ci *
2108c2ecf20Sopenharmony_ci * Function adds configuration key - value entry in the appropriate section
2118c2ecf20Sopenharmony_ci * in the given acceleration device
2128c2ecf20Sopenharmony_ci * To be used by QAT device specific drivers.
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Return: 0 on success, error code otherwise.
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_ciint adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
2178c2ecf20Sopenharmony_ci				const char *section_name,
2188c2ecf20Sopenharmony_ci				const char *key, const void *val,
2198c2ecf20Sopenharmony_ci				enum adf_cfg_val_type type)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *cfg = accel_dev->cfg;
2228c2ecf20Sopenharmony_ci	struct adf_cfg_key_val *key_val;
2238c2ecf20Sopenharmony_ci	struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,
2248c2ecf20Sopenharmony_ci							   section_name);
2258c2ecf20Sopenharmony_ci	if (!section)
2268c2ecf20Sopenharmony_ci		return -EFAULT;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	key_val = kzalloc(sizeof(*key_val), GFP_KERNEL);
2298c2ecf20Sopenharmony_ci	if (!key_val)
2308c2ecf20Sopenharmony_ci		return -ENOMEM;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&key_val->list);
2338c2ecf20Sopenharmony_ci	strlcpy(key_val->key, key, sizeof(key_val->key));
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (type == ADF_DEC) {
2368c2ecf20Sopenharmony_ci		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
2378c2ecf20Sopenharmony_ci			 "%ld", (*((long *)val)));
2388c2ecf20Sopenharmony_ci	} else if (type == ADF_STR) {
2398c2ecf20Sopenharmony_ci		strlcpy(key_val->val, (char *)val, sizeof(key_val->val));
2408c2ecf20Sopenharmony_ci	} else if (type == ADF_HEX) {
2418c2ecf20Sopenharmony_ci		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
2428c2ecf20Sopenharmony_ci			 "0x%lx", (unsigned long)val);
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");
2458c2ecf20Sopenharmony_ci		kfree(key_val);
2468c2ecf20Sopenharmony_ci		return -1;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	key_val->type = type;
2498c2ecf20Sopenharmony_ci	down_write(&cfg->lock);
2508c2ecf20Sopenharmony_ci	adf_cfg_keyval_add(key_val, section);
2518c2ecf20Sopenharmony_ci	up_write(&cfg->lock);
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * adf_cfg_section_add() - Add config section entry to config table.
2588c2ecf20Sopenharmony_ci * @accel_dev:  Pointer to acceleration device.
2598c2ecf20Sopenharmony_ci * @name: Name of the section
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci * Function adds configuration section where key - value entries
2628c2ecf20Sopenharmony_ci * will be stored.
2638c2ecf20Sopenharmony_ci * To be used by QAT device specific drivers.
2648c2ecf20Sopenharmony_ci *
2658c2ecf20Sopenharmony_ci * Return: 0 on success, error code otherwise.
2668c2ecf20Sopenharmony_ci */
2678c2ecf20Sopenharmony_ciint adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *cfg = accel_dev->cfg;
2708c2ecf20Sopenharmony_ci	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (sec)
2738c2ecf20Sopenharmony_ci		return 0;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
2768c2ecf20Sopenharmony_ci	if (!sec)
2778c2ecf20Sopenharmony_ci		return -ENOMEM;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	strlcpy(sec->name, name, sizeof(sec->name));
2808c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sec->param_head);
2818c2ecf20Sopenharmony_ci	down_write(&cfg->lock);
2828c2ecf20Sopenharmony_ci	list_add_tail(&sec->list, &cfg->sec_list);
2838c2ecf20Sopenharmony_ci	up_write(&cfg->lock);
2848c2ecf20Sopenharmony_ci	return 0;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adf_cfg_section_add);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciint adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,
2898c2ecf20Sopenharmony_ci			    const char *section, const char *name,
2908c2ecf20Sopenharmony_ci			    char *value)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct adf_cfg_device_data *cfg = accel_dev->cfg;
2938c2ecf20Sopenharmony_ci	int ret;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	down_read(&cfg->lock);
2968c2ecf20Sopenharmony_ci	ret = adf_cfg_key_val_get(accel_dev, section, name, value);
2978c2ecf20Sopenharmony_ci	up_read(&cfg->lock);
2988c2ecf20Sopenharmony_ci	return ret;
2998c2ecf20Sopenharmony_ci}
300