1// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) 2/* Copyright(c) 2014 - 2020 Intel Corporation */ 3#include <linux/mutex.h> 4#include <linux/slab.h> 5#include <linux/list.h> 6#include <linux/seq_file.h> 7#include "adf_accel_devices.h" 8#include "adf_cfg.h" 9#include "adf_common_drv.h" 10 11static DEFINE_MUTEX(qat_cfg_read_lock); 12 13static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos) 14{ 15 struct adf_cfg_device_data *dev_cfg = sfile->private; 16 17 mutex_lock(&qat_cfg_read_lock); 18 return seq_list_start(&dev_cfg->sec_list, *pos); 19} 20 21static int qat_dev_cfg_show(struct seq_file *sfile, void *v) 22{ 23 struct list_head *list; 24 struct adf_cfg_section *sec = 25 list_entry(v, struct adf_cfg_section, list); 26 27 seq_printf(sfile, "[%s]\n", sec->name); 28 list_for_each(list, &sec->param_head) { 29 struct adf_cfg_key_val *ptr = 30 list_entry(list, struct adf_cfg_key_val, list); 31 seq_printf(sfile, "%s = %s\n", ptr->key, ptr->val); 32 } 33 return 0; 34} 35 36static void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos) 37{ 38 struct adf_cfg_device_data *dev_cfg = sfile->private; 39 40 return seq_list_next(v, &dev_cfg->sec_list, pos); 41} 42 43static void qat_dev_cfg_stop(struct seq_file *sfile, void *v) 44{ 45 mutex_unlock(&qat_cfg_read_lock); 46} 47 48static const struct seq_operations qat_dev_cfg_sops = { 49 .start = qat_dev_cfg_start, 50 .next = qat_dev_cfg_next, 51 .stop = qat_dev_cfg_stop, 52 .show = qat_dev_cfg_show 53}; 54 55DEFINE_SEQ_ATTRIBUTE(qat_dev_cfg); 56 57/** 58 * adf_cfg_dev_add() - Create an acceleration device configuration table. 59 * @accel_dev: Pointer to acceleration device. 60 * 61 * Function creates a configuration table for the given acceleration device. 62 * The table stores device specific config values. 63 * To be used by QAT device specific drivers. 64 * 65 * Return: 0 on success, error code otherwise. 66 */ 67int adf_cfg_dev_add(struct adf_accel_dev *accel_dev) 68{ 69 struct adf_cfg_device_data *dev_cfg_data; 70 71 dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL); 72 if (!dev_cfg_data) 73 return -ENOMEM; 74 INIT_LIST_HEAD(&dev_cfg_data->sec_list); 75 init_rwsem(&dev_cfg_data->lock); 76 accel_dev->cfg = dev_cfg_data; 77 return 0; 78} 79EXPORT_SYMBOL_GPL(adf_cfg_dev_add); 80 81void adf_cfg_dev_dbgfs_add(struct adf_accel_dev *accel_dev) 82{ 83 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; 84 85 dev_cfg_data->debug = debugfs_create_file("dev_cfg", 0400, 86 accel_dev->debugfs_dir, 87 dev_cfg_data, 88 &qat_dev_cfg_fops); 89} 90 91void adf_cfg_dev_dbgfs_rm(struct adf_accel_dev *accel_dev) 92{ 93 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; 94 95 if (!dev_cfg_data) 96 return; 97 98 debugfs_remove(dev_cfg_data->debug); 99 dev_cfg_data->debug = NULL; 100} 101 102static void adf_cfg_section_del_all(struct list_head *head); 103 104void adf_cfg_del_all(struct adf_accel_dev *accel_dev) 105{ 106 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; 107 108 down_write(&dev_cfg_data->lock); 109 adf_cfg_section_del_all(&dev_cfg_data->sec_list); 110 up_write(&dev_cfg_data->lock); 111 clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); 112} 113 114/** 115 * adf_cfg_dev_remove() - Clears acceleration device configuration table. 116 * @accel_dev: Pointer to acceleration device. 117 * 118 * Function removes configuration table from the given acceleration device 119 * and frees all allocated memory. 120 * To be used by QAT device specific drivers. 121 * 122 * Return: void 123 */ 124void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev) 125{ 126 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; 127 128 if (!dev_cfg_data) 129 return; 130 131 down_write(&dev_cfg_data->lock); 132 adf_cfg_section_del_all(&dev_cfg_data->sec_list); 133 up_write(&dev_cfg_data->lock); 134 kfree(dev_cfg_data); 135 accel_dev->cfg = NULL; 136} 137EXPORT_SYMBOL_GPL(adf_cfg_dev_remove); 138 139static void adf_cfg_keyval_add(struct adf_cfg_key_val *new, 140 struct adf_cfg_section *sec) 141{ 142 list_add_tail(&new->list, &sec->param_head); 143} 144 145static void adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec) 146{ 147 struct list_head *head = &sec->param_head; 148 struct list_head *list_ptr, *tmp; 149 150 list_for_each_prev_safe(list_ptr, tmp, head) { 151 struct adf_cfg_key_val *ptr = 152 list_entry(list_ptr, struct adf_cfg_key_val, list); 153 154 if (strncmp(ptr->key, key, sizeof(ptr->key))) 155 continue; 156 157 list_del(list_ptr); 158 kfree(ptr); 159 break; 160 } 161} 162 163static void adf_cfg_keyval_del_all(struct list_head *head) 164{ 165 struct list_head *list_ptr, *tmp; 166 167 list_for_each_prev_safe(list_ptr, tmp, head) { 168 struct adf_cfg_key_val *ptr = 169 list_entry(list_ptr, struct adf_cfg_key_val, list); 170 list_del(list_ptr); 171 kfree(ptr); 172 } 173} 174 175static void adf_cfg_section_del_all(struct list_head *head) 176{ 177 struct adf_cfg_section *ptr; 178 struct list_head *list, *tmp; 179 180 list_for_each_prev_safe(list, tmp, head) { 181 ptr = list_entry(list, struct adf_cfg_section, list); 182 adf_cfg_keyval_del_all(&ptr->param_head); 183 list_del(list); 184 kfree(ptr); 185 } 186} 187 188static struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s, 189 const char *key) 190{ 191 struct list_head *list; 192 193 list_for_each(list, &s->param_head) { 194 struct adf_cfg_key_val *ptr = 195 list_entry(list, struct adf_cfg_key_val, list); 196 if (!strcmp(ptr->key, key)) 197 return ptr; 198 } 199 return NULL; 200} 201 202static struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev, 203 const char *sec_name) 204{ 205 struct adf_cfg_device_data *cfg = accel_dev->cfg; 206 struct list_head *list; 207 208 list_for_each(list, &cfg->sec_list) { 209 struct adf_cfg_section *ptr = 210 list_entry(list, struct adf_cfg_section, list); 211 if (!strcmp(ptr->name, sec_name)) 212 return ptr; 213 } 214 return NULL; 215} 216 217static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev, 218 const char *sec_name, 219 const char *key_name, 220 char *val) 221{ 222 struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name); 223 struct adf_cfg_key_val *keyval = NULL; 224 225 if (sec) 226 keyval = adf_cfg_key_value_find(sec, key_name); 227 if (keyval) { 228 memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES); 229 return 0; 230 } 231 return -ENODATA; 232} 233 234/** 235 * adf_cfg_add_key_value_param() - Add key-value config entry to config table. 236 * @accel_dev: Pointer to acceleration device. 237 * @section_name: Name of the section where the param will be added 238 * @key: The key string 239 * @val: Value pain for the given @key 240 * @type: Type - string, int or address 241 * 242 * Function adds configuration key - value entry in the appropriate section 243 * in the given acceleration device. If the key exists already, the value 244 * is updated. 245 * To be used by QAT device specific drivers. 246 * 247 * Return: 0 on success, error code otherwise. 248 */ 249int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev, 250 const char *section_name, 251 const char *key, const void *val, 252 enum adf_cfg_val_type type) 253{ 254 struct adf_cfg_device_data *cfg = accel_dev->cfg; 255 struct adf_cfg_key_val *key_val; 256 struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev, 257 section_name); 258 char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; 259 260 if (!section) 261 return -EFAULT; 262 263 key_val = kzalloc(sizeof(*key_val), GFP_KERNEL); 264 if (!key_val) 265 return -ENOMEM; 266 267 INIT_LIST_HEAD(&key_val->list); 268 strscpy(key_val->key, key, sizeof(key_val->key)); 269 270 if (type == ADF_DEC) { 271 snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES, 272 "%ld", (*((long *)val))); 273 } else if (type == ADF_STR) { 274 strscpy(key_val->val, (char *)val, sizeof(key_val->val)); 275 } else if (type == ADF_HEX) { 276 snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES, 277 "0x%lx", (unsigned long)val); 278 } else { 279 dev_err(&GET_DEV(accel_dev), "Unknown type given.\n"); 280 kfree(key_val); 281 return -EINVAL; 282 } 283 key_val->type = type; 284 285 /* Add the key-value pair as below policy: 286 * 1. if the key doesn't exist, add it; 287 * 2. if the key already exists with a different value then update it 288 * to the new value (the key is deleted and the newly created 289 * key_val containing the new value is added to the database); 290 * 3. if the key exists with the same value, then return without doing 291 * anything (the newly created key_val is freed). 292 */ 293 if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) { 294 if (strncmp(temp_val, key_val->val, sizeof(temp_val))) { 295 adf_cfg_keyval_remove(key, section); 296 } else { 297 kfree(key_val); 298 return 0; 299 } 300 } 301 302 down_write(&cfg->lock); 303 adf_cfg_keyval_add(key_val, section); 304 up_write(&cfg->lock); 305 return 0; 306} 307EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param); 308 309/** 310 * adf_cfg_section_add() - Add config section entry to config table. 311 * @accel_dev: Pointer to acceleration device. 312 * @name: Name of the section 313 * 314 * Function adds configuration section where key - value entries 315 * will be stored. 316 * To be used by QAT device specific drivers. 317 * 318 * Return: 0 on success, error code otherwise. 319 */ 320int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name) 321{ 322 struct adf_cfg_device_data *cfg = accel_dev->cfg; 323 struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name); 324 325 if (sec) 326 return 0; 327 328 sec = kzalloc(sizeof(*sec), GFP_KERNEL); 329 if (!sec) 330 return -ENOMEM; 331 332 strscpy(sec->name, name, sizeof(sec->name)); 333 INIT_LIST_HEAD(&sec->param_head); 334 down_write(&cfg->lock); 335 list_add_tail(&sec->list, &cfg->sec_list); 336 up_write(&cfg->lock); 337 return 0; 338} 339EXPORT_SYMBOL_GPL(adf_cfg_section_add); 340 341int adf_cfg_get_param_value(struct adf_accel_dev *accel_dev, 342 const char *section, const char *name, 343 char *value) 344{ 345 struct adf_cfg_device_data *cfg = accel_dev->cfg; 346 int ret; 347 348 down_read(&cfg->lock); 349 ret = adf_cfg_key_val_get(accel_dev, section, name, value); 350 up_read(&cfg->lock); 351 return ret; 352} 353EXPORT_SYMBOL_GPL(adf_cfg_get_param_value); 354