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